<?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 Ger]]></title><description><![CDATA[Neueste Beiträge aus Martin Muellers Technologie-Blog]]></description><link>https://martinmueller.dev</link><generator>GatsbyJS</generator><lastBuildDate>Thu, 10 Sep 2026 12:11:00 GMT</lastBuildDate><item><title><![CDATA[Souveräne Cloud auf AWS: Wann reicht eu-central-1 — und wann braucht ihr ESC?]]></title><description><![CDATA[Die AWS European Sovereign Cloud (ESC) ist seit Januar 2026 verfügbar — physisch isolierte EU-Infrastruktur, eigene Partition, EU-resident…]]></description><link>https://martinmueller.dev/aws-esc-de/</link><guid isPermaLink="false">https://martinmueller.dev/aws-esc-de/</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[de]]></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;Die &lt;strong&gt;AWS European Sovereign Cloud (ESC)&lt;/strong&gt; ist seit &lt;strong&gt;Januar 2026&lt;/strong&gt; verfügbar — physisch isolierte EU-Infrastruktur, eigene Partition, EU-resident Operations. In DACH diskutieren viele &lt;strong&gt;digitale Souveränität&lt;/strong&gt;: Datenhoheit, Kontrolle über Betrieb, Unabhängigkeit von Drittstaaten-Zugriff.&lt;/p&gt;
&lt;p&gt;Die Kernfrage:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Reicht &lt;strong&gt;eu-central-1&lt;/strong&gt; (EU-Region), oder braucht ihr die &lt;strong&gt;souveräne Partition&lt;/strong&gt; &lt;code&gt;aws-eusc&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dieser Post ist ein &lt;strong&gt;Builder-Guide&lt;/strong&gt; — keine AWS-Werbung. Ich bin &lt;strong&gt;AWS Solutions Architect Professional&lt;/strong&gt; zertifiziert, &lt;strong&gt;AWS Community Builder&lt;/strong&gt; und unterstütze bei ESC-Migrationen (CDK/Terraform), Souveränitäts-Entscheidungen und Readiness-Checks. &lt;a href=&quot;https://martinmueller.dev/resume-de&quot;&gt;Lebenslauf&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;warum-jetzt&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#warum-jetzt&quot; aria-label=&quot;warum jetzt permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Warum jetzt?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESC GA&lt;/strong&gt; — souveräne AWS-Workloads sind planbar, nicht mehr „irgendwann“&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-Infrastruktur mit eigener Governance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Referenzkunden&lt;/strong&gt; (öffentlich): SCHUFA, ITZBund, SAP, EWE, Swiss Life — Organisationen, die Souveränität als Architektur-Entscheidung treffen&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Politik &amp;#x26; Beschaffung:&lt;/strong&gt; „souveräne Cloud“, EU-only Operations, keine Drittstaaten-Zugriffe — unabhängig vom konkreten Compliance-Framework&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Wenig &lt;strong&gt;deutschsprachiger Builder-Content&lt;/strong&gt; — die meisten Slides verkaufen Souveränität, statt zu erklären was bei Migration technisch bricht.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;was-esc-wirklich-ist--jenseits-von-server-in-der-eu&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-esc-wirklich-ist--jenseits-von-server-in-der-eu&quot; aria-label=&quot;was esc wirklich ist  jenseits von server in der 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;Was ESC wirklich ist — jenseits von „Server in der EU“&lt;/h2&gt;
&lt;p&gt;EU-Region ≠ souveräne Partition. Kurz und sachlich:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspekt&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;Physische Isolation&lt;/td&gt;
&lt;td&gt;EU-Region&lt;/td&gt;
&lt;td&gt;Dedizierte EU-Infra, eigene 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, europäische Governance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Datenresidenz&lt;/td&gt;
&lt;td&gt;Ja (EU)&lt;/td&gt;
&lt;td&gt;Ja (EU) + isolierte Kontroll- und Betriebsebene&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service-Umfang&lt;/td&gt;
&lt;td&gt;Voll&lt;/td&gt;
&lt;td&gt;~90 Services bei GA — wächst&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typischer Käufer&lt;/td&gt;
&lt;td&gt;Die meisten Workloads&lt;/td&gt;
&lt;td&gt;Souveränitäts-kritische Daten &amp;#x26; öffentlicher Sektor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;eu-central-1&lt;/strong&gt; liefert Datenresidenz. &lt;strong&gt;ESC&lt;/strong&gt; liefert zusätzlich Partition-Isolation und EU-gesteuerten Betrieb — das ist der Souveränitäts-Sprung, nicht ein weiteres Zertifikat.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;decision-framework-drei-buckets&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#decision-framework-drei-buckets&quot; aria-label=&quot;decision framework drei 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: drei Buckets&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Zuerst klären: welche Souveränitäts-Anforderung habt ihr?&lt;/strong&gt; — nicht welcher Anbieter am lautesten wirbt.&lt;/p&gt;
&lt;h3 id=&quot;bucket-1--eu-central-1-reicht&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bucket-1--eu-central-1-reicht&quot; aria-label=&quot;bucket 1  eu central 1 reicht permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 reicht&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Workloads, bei denen &lt;strong&gt;EU-Datenresidenz&lt;/strong&gt; genügt&lt;/li&gt;
&lt;li&gt;Kein vertraglicher Zwang zu isolierter Partition oder EU-only Operations&lt;/li&gt;
&lt;li&gt;Ihr wollt AWS-Vollpalette ohne Partition-Split&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Die Mehrheit&lt;/strong&gt; der AWS-Kunden landet hier — und das ist okay&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;bucket-2--esc-für-definierte-workloads&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bucket-2--esc-f%C3%BCr-definierte-workloads&quot; aria-label=&quot;bucket 2  esc für definierte 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 für definierte Workloads&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Vertraglich oder politisch: &lt;strong&gt;souveräne Partition&lt;/strong&gt;, kein Zugriff aus Drittstaaten&lt;/li&gt;
&lt;li&gt;Hochsensible Daten: Gesundheit, Kredit, Bundes-IT, kritische Infrastruktur&lt;/li&gt;
&lt;li&gt;Hybrid: Kern auf ESC, Rest auf eu-central-1 — &lt;strong&gt;phased&lt;/strong&gt;, nicht 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 allein reicht politisch/rechtlich nicht&lt;/li&gt;
&lt;li&gt;Kombination mit On-Prem, BRZ-PaaS (AT), Hetzner, oder dediziertem Hosting&lt;/li&gt;
&lt;li&gt;Bewusste Architektur-Entscheidung — kein Default&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In der Praxis: &lt;strong&gt;Bucket 1 oder 2&lt;/strong&gt;. Souveränität ist Workload-spezifisch, nicht Org-weit.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;was-sich-für-builder-ändert&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-sich-f%C3%BCr-builder-%C3%A4ndert&quot; aria-label=&quot;was sich für builder ändert permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Was sich für Builder ändert&lt;/h2&gt;
&lt;p&gt;Marketing verschweigt die &lt;strong&gt;operativen&lt;/strong&gt; Unterschiede zwischen Partitionen:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Partition &amp;#x26; Identität&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Eigene IAM-Identitäten — keine 1:1-Übernahme aus &lt;code&gt;aws&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ARN-Formate und Account-Struktur neu denken (Landing Zone)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;DNS &amp;#x26; Netzwerk&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Route53-Verhalten und Zonen — häufiger Stolperstein&lt;/li&gt;
&lt;li&gt;Cross-Partition-Referenzen planen oder vermeiden&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;Hardcodierte ARNs aus eu-central-1 brechen&lt;/li&gt;
&lt;li&gt;CI/CD: separate Credentials, ggf. separate Pipelines&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Service-Verfügbarkeit&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Serverless-Stack bei GA — vor Design prüfen&lt;/li&gt;
&lt;li&gt;„In eu-central-1 verfügbar“ ≠ „in ESC verfügbar“&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Typischer Pfad: &lt;strong&gt;Readiness → Landing Zone → Pilot → schrittweise Migration&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;case-studies-wer-setzt-auf-esc&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#case-studies-wer-setzt-auf-esc&quot; aria-label=&quot;case studies wer setzt auf 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: Wer setzt auf ESC?&lt;/h2&gt;
&lt;p&gt;AWS veröffentlicht bei Launch-Kunden meist &lt;strong&gt;Quotes und Richtung&lt;/strong&gt; — selten CDK-Migrationspfade oder Account-Strukturen. Trotzdem lohnt sich ein Blick: &lt;strong&gt;warum&lt;/strong&gt; Organisationen ESC wählen und &lt;strong&gt;was&lt;/strong&gt; öffentlich zum konkreten Einsatz bekannt ist.&lt;/p&gt;
&lt;p&gt;Gemeinsames Muster: nicht Org-weiter Big Bang, sondern &lt;strong&gt;souveränitäts-kritische Workloads&lt;/strong&gt; — oft hybrid neben eu-central-1.&lt;/p&gt;
&lt;h3 id=&quot;schufa--finance--kreditdaten&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#schufa--finance--kreditdaten&quot; aria-label=&quot;schufa  finance  kreditdaten permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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; Kreditdaten&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: souveräne Kreditdaten-Plattform&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;Branche:&lt;/strong&gt; Finanzdaten / Auskunftei&lt;br&gt;
&lt;strong&gt;Warum ESC:&lt;/strong&gt; 69 Mio. Verbraucher-Datensätze; isolierte EU-Infra, nur EU-Personal, kein Zugriff von außerhalb Europa — Souveränität ohne Innovationsverlust.&lt;br&gt;
&lt;strong&gt;Was bekannt ist:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Migration von &lt;strong&gt;On-Prem und anderen Cloud-Workloads&lt;/strong&gt; auf ESC&lt;/li&gt;
&lt;li&gt;Neues &lt;strong&gt;Credit-Scoring-System&lt;/strong&gt; mit transparenter Darstellung für Verbraucher (Kriterien + Gewichtung)&lt;/li&gt;
&lt;li&gt;CTO Klaus Kolitz: Innovation und Souveränität zusammen, nicht entweder/oder&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Quellen:&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-meter--kritische-infrastruktur&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#diehl-metering--smart-meter--kritische-infrastruktur&quot; aria-label=&quot;diehl metering  smart meter  kritische infrastruktur permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 Meter &amp;#x26; kritische Infrastruktur&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: souveräne Messdaten-Plattform&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;Branche:&lt;/strong&gt; Smart Metering (Wasser/Energie), B2B2G&lt;br&gt;
&lt;strong&gt;Warum ESC:&lt;/strong&gt; Öffentliche Kunden (Stadtwerke, Wasserwerke) verlangen EU-Datenhaltung und EU-Betrieb.&lt;br&gt;
&lt;strong&gt;Was bekannt ist:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Smart-Metering-Datenplattform&lt;/strong&gt; auf ESC&lt;/li&gt;
&lt;li&gt;Modulare Services: &lt;strong&gt;Monitoring, Billing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Zentrales System für Wasser-/Energiedaten kritischer Infrastruktur&lt;/li&gt;
&lt;li&gt;Skalierung der Plattform ohne den Aufwand eines komplett eigenen Sovereign-Stacks&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Quellen:&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 (Mai 2026)&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;universitätsklinikum-essen--sovereign-ai-in-der-medizin&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#universit%C3%A4tsklinikum-essen--sovereign-ai-in-der-medizin&quot; aria-label=&quot;universitätsklinikum essen  sovereign ai in der medizin permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Universitätsklinikum Essen — Sovereign AI in der Medizin&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: souveräne KI-Forschung&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;Branche:&lt;/strong&gt; Universitätsmedizin / Forschung&lt;br&gt;
&lt;strong&gt;Warum ESC:&lt;/strong&gt; Health Data at Scale unter deutschen und europäischen Souveränitäts-Erwartungen.&lt;br&gt;
&lt;strong&gt;Was bekannt ist:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IKIM&lt;/strong&gt; (Institut für KI in der Medizin) nutzt ESC als Basis für KI-Forschung&lt;/li&gt;
&lt;li&gt;Ziel: medizinische Forschung in die Klinik überführen — mit Patientendaten in souveräner Umgebung&lt;/li&gt;
&lt;li&gt;Eher &lt;strong&gt;Transformations- und Forschungspfad&lt;/strong&gt; als dokumentierte Vollmigration eines Klinik-ERP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Quellen:&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--regionales-gesundheitsökosystem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#medizinische-universit%C3%A4t-lausitz--carl-thiem--regionales-gesundheits%C3%B6kosystem&quot; aria-label=&quot;medizinische universität lausitz  carl thiem  regionales gesundheitsökosystem permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 — regionales Gesundheitsökosystem&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Branche:&lt;/strong&gt; Gesundheit / Forschung (Brandenburg)&lt;br&gt;
&lt;strong&gt;Warum ESC:&lt;/strong&gt; Souveräne digitale Basis für das „Gesundheitsmodellregion Lausatia“.&lt;br&gt;
&lt;strong&gt;Was bekannt ist:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vernetzung von &lt;strong&gt;Krankenhäusern, Forschung, regionalen Partnern&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Sichere, souveräne Grundlage für Care, Research, Education&lt;/li&gt;
&lt;li&gt;Nähe zur 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;Quelle:&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--bundes-it&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#itzbund--bundes-it&quot; aria-label=&quot;itzbund  bundes 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 — Bundes-IT&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Branche:&lt;/strong&gt; Öffentlicher Sektor&lt;br&gt;
&lt;strong&gt;Warum ESC:&lt;/strong&gt; Zentraler IT-Dienstleister des Bundes — strengste Anforderungen an Schutz und Souveränität.&lt;br&gt;
&lt;strong&gt;Was bekannt ist:&lt;/strong&gt; Commitment zu ESC mit voller AWS-Service-Palette; &lt;strong&gt;keine&lt;/strong&gt; öffentliche Workload-Liste (erwartbar bei Bundes-IT).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quelle:&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--energie&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ewe-ag--energie&quot; aria-label=&quot;ewe ag  energie permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 — Energie&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Branche:&lt;/strong&gt; Energie / Versorger&lt;br&gt;
&lt;strong&gt;Warum ESC:&lt;/strong&gt; Sensible Versorgungsdaten und kritische Infrastruktur; Souveränität als Plattform-Strategie.&lt;br&gt;
&lt;strong&gt;Was bekannt ist:&lt;/strong&gt; ESC als Baustein der &lt;strong&gt;Plattform-Strategie&lt;/strong&gt; — kein einzelnes benanntes Produkt, aber klarer strategischer Einsatz.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quelle:&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-denken&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#eterno-health--health-saas-hybrid-denken&quot; aria-label=&quot;eterno health  health saas hybrid denken permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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-Denken)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Branche:&lt;/strong&gt; Ambulante Versorgung / Praxissoftware&lt;br&gt;
&lt;strong&gt;Warum ESC:&lt;/strong&gt; EU-weite Digitalisierung der Ambulanz — Kunden mit expliziten Souveränitäts-Anforderungen.&lt;br&gt;
&lt;strong&gt;Was bekannt ist:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gesamter Stack bisher auf Standard-AWS; ESC als &lt;strong&gt;zusätzliche Option&lt;/strong&gt; für sovereignty-sensitive Deployments&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leni&lt;/strong&gt; — KI-Agent (Transkription, Zusammenfassung, Patientenakte) in eigenen Test-Kliniken&lt;/li&gt;
&lt;li&gt;Muster: SaaS auf AWS, ESC-Partition für Kunden die sie brauchen&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Quellen:&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;plattform-partner-keine-endkunden-aber-relevant&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#plattform-partner-keine-endkunden-aber-relevant&quot; aria-label=&quot;plattform partner keine endkunden aber 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;Plattform-Partner (keine Endkunden, aber relevant)&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Anbieter&lt;/th&gt;
&lt;th&gt;Was auf ESC&lt;/th&gt;
&lt;th&gt;Souveränitäts-Winkel&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 unter 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;Klinik-Software (540M+ Patienten)&lt;/td&gt;
&lt;td&gt;Klinische Workflows mit 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;Healthcare-Digitalisierung souverän&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Quellen:&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;Was öffentlich fehlt&lt;/strong&gt; — und wo Readiness-Assessments ansetzen: IAM/Landing-Zone-Design, CDK-Migrationspfade, Timeline, Kosten. Die Lücke zwischen Marketing-Quote und Production-Migration ist groß.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;esc-vs-eu-hosting-auf-hetzner&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#esc-vs-eu-hosting-auf-hetzner&quot; aria-label=&quot;esc vs eu hosting auf 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 auf Hetzner&lt;/h2&gt;
&lt;p&gt;Ich habe &lt;a href=&quot;/hetzner-eu-production-de&quot;&gt;Prod auf Hetzner für EU-Kunden&lt;/a&gt; beschrieben — &lt;strong&gt;Arc Rider Universe&lt;/strong&gt; mit voller Datenhoheit auf 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;Souveränitäts-Modell&lt;/td&gt;
&lt;td&gt;Du betreibst alles&lt;/td&gt;
&lt;td&gt;AWS-native souveräne Partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zielgruppe&lt;/td&gt;
&lt;td&gt;Neues Produkt, volle Kontrolle&lt;/td&gt;
&lt;td&gt;Bestehender AWS-Shop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ops-Last&lt;/td&gt;
&lt;td&gt;Hoch&lt;/td&gt;
&lt;td&gt;Niedriger (managed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typischer Pfad&lt;/td&gt;
&lt;td&gt;SaaS mit EU-Prod-Pflicht&lt;/td&gt;
&lt;td&gt;Migration souveränitäts-kritischer AWS-Workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Beides kann parallel — &lt;strong&gt;Hybrid&lt;/strong&gt; ist normal. Souveränität ist kein Either/Or.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;cloud-act--drittstaaten-zugriff--ehrlich&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cloud-act--drittstaaten-zugriff--ehrlich&quot; aria-label=&quot;cloud act  drittstaaten zugriff  ehrlich permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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; Drittstaaten-Zugriff — ehrlich&lt;/h2&gt;
&lt;p&gt;Das ist der Souveränitäts-Elefant im Raum. &lt;strong&gt;eu-central-1&lt;/strong&gt; hostet in der EU, aber die Partition bleibt &lt;code&gt;aws&lt;/code&gt;. &lt;strong&gt;ESC&lt;/strong&gt; adressiert genau das:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Physisch isolierte Infrastruktur in der EU&lt;/li&gt;
&lt;li&gt;EU-resident Operations — kein globaler Ops-Zugriff aus den USA&lt;/li&gt;
&lt;li&gt;Europäische Governance-Struktur&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Was ESC &lt;strong&gt;nicht&lt;/strong&gt; ersetzt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vertragsprüfung (Unterauftragnehmer, Support-Pfade)&lt;/li&gt;
&lt;li&gt;Datenklassifikation — welche Workloads brauchen welches Souveränitäts-Level&lt;/li&gt;
&lt;li&gt;Politische Erwartungen vs. technische Realität&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ehrliche Einordnung schlägt Marketing. Souveränität ist Architektur &lt;strong&gt;und&lt;/strong&gt; Vertrag.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;nächster-schritt-esc-readiness-assessment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#n%C3%A4chster-schritt-esc-readiness-assessment&quot; aria-label=&quot;nächster schritt 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;Nächster Schritt: ESC Readiness Assessment&lt;/h2&gt;
&lt;p&gt;Wenn ihr AWS nutzt oder plant und Souveränität klären wollt:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;45 Minuten, kein Pitch:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Welcher &lt;strong&gt;Bucket&lt;/strong&gt; (1/2/3) für eure Workloads&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CDK/Terraform-Stolpersteine&lt;/strong&gt; (IAM, Route53, Partition)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Migrations-Fahrplan&lt;/strong&gt; — Pilot → Rollout, Hybrid wo sinnvoll&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Talk auf dem &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;Kontakt:&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-de&quot;&gt;Lebenslauf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Betreff: &lt;em&gt;ESC Readiness&lt;/em&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;weiterführend&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#weiterf%C3%BChrend&quot; aria-label=&quot;weiterführend permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Weiterführend&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; (offiziell)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/hetzner-eu-production-de&quot;&gt;Produktion auf Hetzner (EU)&lt;/a&gt; — Souveränität ohne 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 drei Monate später: Was wirklich gelandet ist]]></title><description><![CDATA[Im April habe ich über OpenClaw geschrieben — mein selbst gehosteter KI-Agent auf einem Hostinger-VPS, angebunden an Telegram, E-Mail…]]></description><link>https://martinmueller.dev/openclaw-three-months-later-de/</link><guid isPermaLink="false">https://martinmueller.dev/openclaw-three-months-later-de/</guid><category><![CDATA[de]]></category><category><![CDATA[2026]]></category><category><![CDATA[openclaw]]></category><category><![CDATA[ai]]></category><category><![CDATA[automation]]></category><category><![CDATA[mcp]]></category><category><![CDATA[cursor]]></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;Im &lt;a href=&quot;https://martinmueller.dev/openclaw-de&quot;&gt;April habe ich über OpenClaw geschrieben&lt;/a&gt; — mein selbst gehosteter KI-Agent auf einem &lt;a href=&quot;https://www.hostinger.com/de?REFERRALCODE=MARTINMUELLER&quot;&gt;Hostinger&lt;/a&gt;-VPS, angebunden an Telegram, E-Mail, Kalender und GitHub. Der Post endete mit einer kurzen „What&apos;s Next“-Liste. Drei Monate später ist das meiste umgesetzt — und das Setup fühlt sich weniger wie ein Chatbot und mehr wie ein kleines Ops-Team an.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Neu seit April:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blogposts&lt;/strong&gt; — Sprachnachricht rein, recherchierter Entwurf raus, auf der Site veröffentlicht&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code aus GitHub-Issues&lt;/strong&gt; — Agent plant, ich approve, PR kommt&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rechnungen&lt;/strong&gt; — zweisprachige PDFs für US- und DE-Kunden, Mail-Entwurf fertig&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO &amp;#x26; Compliance&lt;/strong&gt; — Live-Daten und Reports ohne fünf Tools anklicken&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ein Telegram-Chat, viele Projekte&lt;/strong&gt; — Topics trennen den Kontext&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Konferenz-Vorschläge&lt;/strong&gt; — Talk-Entwürfe aus Memory, nicht von null&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Was sich geändert hat, was kaputtging und was ich wieder so machen würde.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;kurz-zusammengefasst&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#kurz-zusammengefasst&quot; aria-label=&quot;kurz zusammengefasst permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Kurz zusammengefasst&lt;/h2&gt;
&lt;p&gt;OpenClaw ist ein persistenter Assistent mit Gedächtnis. Ich rede vor allem per &lt;strong&gt;Telegram&lt;/strong&gt; — oft per Sprachnachricht. Er kann Aufgaben ausführen, Repos lesen, E-Mails entwerfen, GitHub prüfen. Versand nur nach meinem OK.&lt;/p&gt;
&lt;p&gt;Alles Folgende baut darauf auf.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;1-blogposts--von-der-idee-bis-live&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-blogposts--von-der-idee-bis-live&quot; aria-label=&quot;1 blogposts  von der idee bis 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;1. Blogposts — von der Idee bis live&lt;/h2&gt;
&lt;p&gt;Im April-Post stand: Blogposts entwerfen. Passiert — mehrfach:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Post&lt;/th&gt;
&lt;th&gt;Was der Agent gemacht hat&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-de&quot;&gt;Hetzner-EU-Prod-Serie&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Recherche, EN+DE-Entwurf, Bilder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/lovable-hetzner-germany-de&quot;&gt;Lovable → Hetzner DACH&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Gleiche Formel, echte Kundenstory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/sistrix-mcp-hallocasa-seo-de&quot;&gt;SISTRIX-MCP-SEO-Audit&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Live-SEO-Daten, Kunden-Code gelesen, Strategie-PDF&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Typischer Ablauf: Sprachnachricht → Kontext aus Notizen und Repos → Markdown-Entwurf → ich kürze und prüfe den Ton → veröffentlichen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Stark bei Erstentwürfen mit echten Daten. Mein Job: „Würde ich das unter meinem Namen posten?“&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;2-github-issues--plan--pr&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-github-issues--plan--pr&quot; aria-label=&quot;2 github issues  plan  pr permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 → Plan → PR&lt;/h2&gt;
&lt;p&gt;Größtes Upgrade: OpenClaw kann Coding an &lt;a href=&quot;https://cursor.com&quot;&gt;Cursor&lt;/a&gt; im echten Repo abgeben.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Heute:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Neues Issue im Produkt-Repo eines Kunden&lt;/li&gt;
&lt;li&gt;Ping auf Telegram&lt;/li&gt;
&lt;li&gt;Agent schreibt Implementierungsplan aus dem Code&lt;/li&gt;
&lt;li&gt;Plan als &lt;strong&gt;GitHub-Kommentar&lt;/strong&gt; — für das Team sichtbar, nicht im Chat versteckt&lt;/li&gt;
&lt;li&gt;Ich approve → Code wird geschrieben → PR&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Kleine Checks laufen auf dem günstigen Modell; Planung und Code nur, wenn es sich lohnt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Plan im Repo und auf GitHub halten. Telegram für Pings und Entscheidungen.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3-rechnungen--die-langweilige-arbeit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-rechnungen--die-langweilige-arbeit&quot; aria-label=&quot;3 rechnungen  die langweilige arbeit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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. Rechnungen — die langweilige Arbeit&lt;/h2&gt;
&lt;p&gt;Rechnungstag war früher: HTML kopieren, Sätze suchen, USt-Formulierung prüfen, PDF, Upload, Begleitmail. Heute öffne ich das richtige Telegram-Topic und sage &lt;em&gt;nächste Rechnung vorbereiten&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Der Agent kennt die Regeln pro Kunde — US vs. deutsch, Währung, MwSt, Layout. Letzte Rechnung als Vorlage, Nummer hoch, Zeitraum und Positionen eintragen, nur nachfragen was fehlt. Ergebnis: PDF in Dropbox, Mail-Entwurf wartet — &lt;strong&gt;Versand erst nach meinem OK&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Der ROI-stärkste Use Case aus den letzten drei Monaten. Repetitiv, regellastig, fehleranfällig. Genau dafür ein Agent mit Gedächtnis.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;4-seo-wordpress-compliance--ein-prompt-ein-ergebnis&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#4-seo-wordpress-compliance--ein-prompt-ein-ergebnis&quot; aria-label=&quot;4 seo wordpress compliance  ein prompt ein ergebnis permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 — ein Prompt, ein Ergebnis&lt;/h2&gt;
&lt;p&gt;April: Basis-Gedächtnis und wenige Tools. Juli: Der Agent spricht mit Diensten, die ich wöchentlich brauche — SEO-Daten, Kunden-WordPress, Security-Scan-Reports.&lt;/p&gt;
&lt;p&gt;Immer gleiches Muster: eine Telegram-Nachricht, Agent kombiniert Live-Daten + Code-Kontext, ich bekomme ein datiertes Ergebnis (Markdown, PDF oder Issue-Kommentar). Den SEO-Workflow habe ich &lt;a href=&quot;/sistrix-mcp-hallocasa-seo-de&quot;&gt;hier&lt;/a&gt; beschrieben.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Eine Integration pro Aufgabe, die du monatlich manuell wiederholst. Nicht am ersten Tag alles verdrahten.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;5-telegram-topics--projekt-switcher&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-telegram-topics--projekt-switcher&quot; aria-label=&quot;5 telegram topics  projekt 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 = Projekt-Switcher&lt;/h2&gt;
&lt;p&gt;Ein Gruppenchat, viele &lt;strong&gt;Topics&lt;/strong&gt; — Blog, US-Kunde, DE-Kunde, Nebenprojekte.&lt;/p&gt;
&lt;p&gt;Jedes Topic lädt den passenden Kontext: welches Repo, welcher Ton, welche Regeln. Kein Rechnungsgespräch im Blog-Thread.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Wenn der Bot in der Gruppe schweigt — aktuelle OpenClaw-Version prüfen. Forum-Topics hatten einen Reply-Bug, der inzwischen gefixt ist.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;6-konferenz-talk-entwürfe&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#6-konferenz-talk-entw%C3%BCrfe&quot; aria-label=&quot;6 konferenz talk entwürfe permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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. Konferenz-Talk-Entwürfe&lt;/h2&gt;
&lt;p&gt;Neben Kundenarbeit reiche ich bei AWS Community Days, AgentCon, CodeMotion, re:Invent ein. Der Agent hält Vorschlags-Entwürfe in einem Ordner und kennt das Submission-Format.&lt;/p&gt;
&lt;p&gt;Typischer Ablauf: &lt;em&gt;Talk zu Security-Scanning für Poland Community Day entwerfen&lt;/em&gt; → Agent zieht aus früheren Projekten und Talks → Titel, Abstract, Gliederung paste-ready → Kalender-Reminder für die Deadline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; CFP = Recherche + Struktur + deine Stimme. Der Agent macht die ersten beiden.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;zahlen-grob-drei-monate&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zahlen-grob-drei-monate&quot; aria-label=&quot;zahlen grob drei monate permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zahlen (grob, drei Monate)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; viele Issues triagiert; mehrere Fixes via Agent → Cursor → PR&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blog:&lt;/strong&gt; 4+ substanzielle Posts mit Agent-Hilfe (EN+DE)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rechnungen:&lt;/strong&gt; 5+ US-Sprint-Rechnungen + deutsche Kundenrechnungen — jeweils PDF + Mail-Entwurf&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CFP:&lt;/strong&gt; 10+ Vorschlags-Entwürfe für Polen, DACH, Mailand, re:Invent&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kosten:&lt;/strong&gt; richtiges Modell pro Aufgabe wichtiger als VPS-Hosting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pannen:&lt;/strong&gt; eine Mail zu früh raus → harte „vor Versand fragen“-Regel; Morgen-Briefing einmal nach Update kaputt — mit Versions-Update und günstigerem Cron-Job gefixt&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;was-als-nächstes-kommt&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-als-n%C3%A4chstes-kommt&quot; aria-label=&quot;was als nächstes kommt permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Was als Nächstes kommt&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Auto-Implement nach explizitem GitHub-Approve&lt;/li&gt;
&lt;li&gt;Infra aus dem Chat (Hetzner in Arbeit)&lt;/li&gt;
&lt;li&gt;USt-Voranmeldung aus Rechnungsordner — agent-unterstützt, Steuerberater prüft&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;fazit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fazit&quot; aria-label=&quot;fazit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fazit&lt;/h2&gt;
&lt;p&gt;Vor drei Monaten: E-Mail, Kalender, GitHub-Pings. Heute: &lt;strong&gt;Orchestrator&lt;/strong&gt; — Topics für Kontext, Cursor für Code, Live-Integrationen für Daten, Blog für Content, Rechnungen und Talk-Entwürfe für die Business-Seite.&lt;/p&gt;
&lt;p&gt;Weiterhin &lt;strong&gt;€10/mo &lt;a href=&quot;https://www.hostinger.com/de?REFERRALCODE=MARTINMUELLER&quot;&gt;Hostinger&lt;/a&gt; Docker&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Wenn du OpenClaw schon nutzt: für mich die größten Hebel — &lt;strong&gt;Coding an Cursor abgeben&lt;/strong&gt;, &lt;strong&gt;ein Telegram-Topic pro Kunde/Projekt&lt;/strong&gt;, &lt;strong&gt;eine Integration pro repetitiver manueller Aufgabe&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-de&quot;&gt;Original-OpenClaw-Post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/peachbase-global-brain&quot;&gt;PeachBase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/sistrix-mcp-hallocasa-seo-de&quot;&gt;SISTRIX-MCP-Fallstudie&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;Fragen oder Hilfe beim Setup? &lt;a href=&quot;mailto:office@martinmueller.dev&quot;&gt;office@martinmueller.dev&lt;/a&gt; oder &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[Datengetriebenes SEO mit dem SISTRIX MCP: Ein HalloCasa Case Study]]></title><description><![CDATA[Ich habe HalloCasa mitgegründet — ein globales Maklerverzeichnis mit Listings, Profilen, Abos und Kursen. Organische Suche sollte für uns…]]></description><link>https://martinmueller.dev/sistrix-mcp-hallocasa-seo-de/</link><guid isPermaLink="false">https://martinmueller.dev/sistrix-mcp-hallocasa-seo-de/</guid><category><![CDATA[de]]></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;Ich habe &lt;a href=&quot;https://hallocasa.com&quot;&gt;HalloCasa&lt;/a&gt; mitgegründet — ein globales Maklerverzeichnis mit Listings, Profilen, Abos und Kursen. Organische Suche sollte für uns ein wichtiger Kanal sein. Als ich mich hinsetzte, eine SEO-Strategie zu bauen, wollte ich keinen Tag in Dashboards klicken, CSVs exportieren und Screenshots in ein Doc kleben.&lt;/p&gt;
&lt;p&gt;Stattdessen habe ich meine KI in &lt;strong&gt;Cursor&lt;/strong&gt; mit dem &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; verbunden und in einer Agent-Session ein vollständiges Audit gefahren: Sichtbarkeits-Baseline über mehrere Märkte, Ranking-URLs, Keyword-Chancen, Wettbewerber-Overlap, Backlink-Profil — abgeglichen mit unserer Next.js-Codebase zu Canonical-Tags, hreflang und Sitemaps. Ergebnis: eine priorisierte Roadmap, kein Bauchgefühl.&lt;/p&gt;
&lt;p&gt;Alles begann mit einem 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;Keine Keyword-Spreadsheets, kein ausgefeilter System-Prompt — nur Domain und Tool. Von dort zog der Agent SISTRIX-Daten Markt für Markt, las unser Repo und machte daraus ein Strategie-Dokument mit priorisierten Stufen.&lt;/p&gt;
&lt;p&gt;Dieser Post beschreibt den Workflow: was SISTRIX und sein MCP sind, warum MCP für SEO relevant ist, und was die Daten über hallocasa.com erzählt haben.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;was-ist-sistrix&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-ist-sistrix&quot; aria-label=&quot;was ist 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;Was ist SISTRIX?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.sistrix.com/&quot;&gt;SISTRIX&lt;/a&gt; ist eine deutsche SEO-Plattform, weit verbreitet im DACH-Raum und darüber hinaus. Die Leitmetrik ist der &lt;strong&gt;Sichtbarkeitsindex&lt;/strong&gt; — ein Score aus Ranking-Positionen und Suchvolumen über alle Keywords, für die eine Domain rankt. Dazu kommen Keyword-Rankings, Backlink-Daten, Wettbewerber-Overlap, Suchintention und (neuer) AI-Visibility-Tooling.&lt;/p&gt;
&lt;p&gt;Für eine Site wie HalloCasa — globales Maklerverzeichnis, LatAm-lastige Länderliste, deutschsprachiger Expat-Content im Blog — ist SISTRIX nützlich, weil man nach &lt;strong&gt;Land&lt;/strong&gt; slicen kann (&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;, …) und Märkte in einer Session vergleicht, statt anzunehmen, ein Google-Index passe für alle.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;warum-mcp-für-seo-tools&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#warum-mcp-f%C3%BCr-seo-tools&quot; aria-label=&quot;warum mcp für 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;Warum MCP für SEO-Tools?&lt;/h2&gt;
&lt;p&gt;Das &lt;a href=&quot;https://modelcontextprotocol.io/&quot;&gt;Model Context Protocol (MCP)&lt;/a&gt; ist ein offener Standard, mit dem KI-Assistenten externe Tools über eine einheitliche Schnittstelle aufrufen. Ohne MCP raten Chatbots oder halluzinieren Metriken. Mit MCP ziehen sie &lt;strong&gt;Live-Daten&lt;/strong&gt; aus der SEO-Plattform.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ohne MCP&lt;/th&gt;
&lt;th&gt;Mit MCP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tab-Hopping, manuelle Exports&lt;/td&gt;
&lt;td&gt;Agent fragt Live-Daten im Chat ab&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Veraltete Screenshots in Strategie-Docs&lt;/td&gt;
&lt;td&gt;Reproduzierbare, datierte API-Pulls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEO-Analyst und Entwickler in getrennten Tools&lt;/td&gt;
&lt;td&gt;Agent gleicht Rankings &lt;strong&gt;und&lt;/strong&gt; Repo ab&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Unter &lt;strong&gt;Cursor → Settings → Tools &amp;#x26; MCP&lt;/strong&gt; verdrahtet man den SISTRIX-Server einmal. Der Agent ruft dann Tools wie &lt;code&gt;domain_visindex&lt;/code&gt; oder &lt;code&gt;keyword_domain_seo&lt;/code&gt; im normalen Chat auf — wie Dateien lesen oder Terminal-Befehle.&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;Schritt&lt;/th&gt;
&lt;th&gt;Du&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;SEO-Audit deiner Domain anfragen&lt;/td&gt;
&lt;td&gt;Ruft SISTRIX-MCP-Tools pro Markt auf&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Agent auf Repo zeigen&lt;/td&gt;
&lt;td&gt;Liest &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;Strategie + Prioritäten anfragen&lt;/td&gt;
&lt;td&gt;Synthetisiert Daten + Code-Funde zu actionable Doc&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;sistrix-mcp-einrichten&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sistrix-mcp-einrichten&quot; aria-label=&quot;sistrix mcp einrichten permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 einrichten&lt;/h2&gt;
&lt;p&gt;SISTRIX liefert einen offiziellen MCP-Server. Docs und Setup-Guides:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ressource&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;Haupt-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 für alle Pläne (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;Technische Referenz&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 funktioniert inzwischen auf &lt;strong&gt;allen SISTRIX-Plänen&lt;/strong&gt; — einloggen, kein API-Key nötig. API-Keys gehen weiter auf Plus+, wenn man will. Laut &lt;a href=&quot;https://www.sistrix.com/api/connection-to-chatbot-ai/technical-information-mcp/&quot;&gt;SISTRIX-Docs&lt;/a&gt; verbrauchen MCP-Requests aktuell &lt;strong&gt;keine API-Credits&lt;/strong&gt; (anders als direkte API-Calls). Für Cursor: MCP-Server mit demselben Endpoint plus OAuth oder API-Key in der MCP-Config.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;sistrix-mcp-tool-oberfläche&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sistrix-mcp-tool-oberfl%C3%A4che&quot; aria-label=&quot;sistrix mcp tool oberfläche permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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-Oberfläche&lt;/h2&gt;
&lt;p&gt;Der MCP exponiert Dutzende Tools. Im HalloCasa-Audit haben wir diese Gruppen genutzt:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Kategorie&lt;/th&gt;
&lt;th&gt;Beispiel-Tools&lt;/th&gt;
&lt;th&gt;Was man lernt&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Domain-Sichtbarkeit&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 pro Markt, Page-1-Keyword-Anzahl&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;Was rankt, Near-Wins, Volumen und Intent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wettbewerb&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 und 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;Toxische vs. legitime Backlinks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI-Sichtbarkeit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ai_entity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;AEO-Baseline (unser HalloCasa-Entity-Call lieferte HTTP 500)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Projekte&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;Laufendes Tracking, sobald ein Projekt existiert&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;country&lt;/code&gt;&lt;/strong&gt; als ISO-Code übergeben (&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;, …), um mehrere Märkte in einer Session zu auditieren. So sahen wir: Deutschland hat Historie, Kolumbien und Mexiko praktisch keine Sichtbarkeit.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;hallocasa-case-study-was-die-daten-zeigten&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hallocasa-case-study-was-die-daten-zeigten&quot; aria-label=&quot;hallocasa case study was die daten zeigten permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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: Was die Daten zeigten&lt;/h2&gt;
&lt;p&gt;Domain: &lt;strong&gt;hallocasa.com&lt;/strong&gt;. Der Agent zog SISTRIX-Daten über unsere Hauptmärkte (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;Deutschland ist der einzige Markt mit relevanter organischer Historie — die Sichtbarkeit ist seit einem Peak vor ein paar Jahren stark gesunken. USA und Spanien zeigen Spuren (meist Blog-Content). Kolumbien und Mexiko haben trotz Kern-Geschäftsgeografie praktisch keinen organischen Footprint.&lt;/p&gt;
&lt;p&gt;Diese Diskrepanz zwischen Business-Fokus und Search-Sichtbarkeit war der erste große Insight — sichtbar nur, weil wir pro Land abgefragt haben statt Google als einen globalen Index zu behandeln.&lt;/p&gt;
&lt;h3 id=&quot;wo-rankings-wirklich-liegen&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wo-rankings-wirklich-liegen&quot; aria-label=&quot;wo rankings wirklich liegen permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wo Rankings wirklich liegen&lt;/h3&gt;
&lt;p&gt;Fast der gesamte SEO-Wert sitzt auf &lt;strong&gt;&lt;code&gt;blog.hallocasa.com&lt;/code&gt;&lt;/strong&gt;, meist deutsche Artikel zu LatAm-Immobilien (Chile, Kolumbien, Peru, Argentinien, Mexiko). Das &lt;strong&gt;Verzeichnis&lt;/strong&gt; (&lt;code&gt;www.hallocasa.com&lt;/code&gt;) rankt im Vergleich kaum — ein paar Makler-Namen-Profil-Queries, sonst wenig.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kernbefund:&lt;/strong&gt; Autorität strandet auf einer Subdomain, fließt nicht zu Makler-Profilen und &lt;code&gt;/brokers&lt;/code&gt;. Strukturproblem, kein Content-Gap.&lt;/p&gt;
&lt;h3 id=&quot;near-win-keywords-schnellster-ranking-upside&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#near-win-keywords-schnellster-ranking-upside&quot; aria-label=&quot;near win keywords schnellster 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 (schnellster Ranking-Upside)&lt;/h3&gt;
&lt;p&gt;SISTRIX &lt;code&gt;domain_opportunities&lt;/code&gt; zeigte mehrere deutsche Keywords, bei denen wir schon auf Seite 2 ranken — grenzüberschreitende Investment- und Expat-Immobilienthemen mit relativ geringem Wettbewerb. Die auf Seite 1 zu schieben ist weniger Aufwand als neue Head-Terms.&lt;/p&gt;
&lt;h3 id=&quot;wettbewerber-de-organischer-overlap&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wettbewerber-de-organischer-overlap&quot; aria-label=&quot;wettbewerber de organischer 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;Wettbewerber (DE organischer Overlap)&lt;/h3&gt;
&lt;p&gt;Die Overlap-Menge mischt große deutsche Immobilienportale, internationale Luxury-Listing-Sites und Nischen-Expat-/Investment-Blogs. Wir konkurrieren nicht um generische deutsche Portal-Head-Terms; unsere Nische ist &lt;strong&gt;grenzüberschreitender / Expat-Investor-Content&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;backlinks-meist-rauschen&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#backlinks-meist-rauschen&quot; aria-label=&quot;backlinks meist rauschen permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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: meist Rauschen&lt;/h3&gt;
&lt;p&gt;Das Linkprofil wird von &lt;strong&gt;SEO-Verzeichnis- und PBN-Spam&lt;/strong&gt; dominiert. Legitime Links gibt es, aber spärlich — Partner-Podcasts, Reise-Sites, Konferenz-Medien. GSC-Audit vor Disavow sinnvoll; Google ignoriert offensichtlichen Spam oft von selbst.&lt;/p&gt;
&lt;h3 id=&quot;code-abgleich-warum-das-verzeichnis-nicht-rankt&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code-abgleich-warum-das-verzeichnis-nicht-rankt&quot; aria-label=&quot;code abgleich warum das verzeichnis nicht rankt permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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-Abgleich: Warum das Verzeichnis nicht rankt&lt;/h3&gt;
&lt;p&gt;Der Agent las unser Next.js-Repo parallel zu SISTRIX-URLs. Technische Punkte, die schwache Verzeichnis-Sichtbarkeit erklären:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;i18n via &lt;code&gt;?lang=&lt;/code&gt;&lt;/strong&gt; im Verzeichnis, aber &lt;strong&gt;Canonical-URLs strippen den Query&lt;/strong&gt; — alle neun Locales kollabieren auf eine indexierbare URL pro Pfad.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kein &lt;code&gt;hreflang&lt;/code&gt;&lt;/strong&gt;; Blog und Home nutzen Pfad-Locales (&lt;code&gt;/de/&lt;/code&gt;, &lt;code&gt;/es/&lt;/code&gt;), Apex Query-Locales.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fragmentierte Architektur:&lt;/strong&gt; &lt;code&gt;blog.&lt;/code&gt;, &lt;code&gt;home.&lt;/code&gt; und Apex als getrennte Properties; der Blog hält die Rankings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;International SEO fixen und Blog-Autorität auf die Hauptdomain konsolidieren sind Grundlagen, bevor Content in CO/MX skaliert wird.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;priorisierte-roadmap-90-tage-perspektive&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#priorisierte-roadmap-90-tage-perspektive&quot; aria-label=&quot;priorisierte roadmap 90 tage perspektive permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Priorisierte Roadmap (90-Tage-Perspektive)&lt;/h2&gt;
&lt;p&gt;Aus dem Audit haben wir Aktionen nach Aufwand vs. Impact gestaffelt:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P0 — zuerst (Wochen 1–4)&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aktion&lt;/th&gt;
&lt;th&gt;Warum&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;Ohne Messung geht nichts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;www&lt;/code&gt;-Canonical + 301 aller Host-Varianten&lt;/td&gt;
&lt;td&gt;Stoppt gesplittete Link-Equity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blog → Verzeichnis-CTAs auf Top-DE-Posts&lt;/td&gt;
&lt;td&gt;Rankings da; Verzeichnis bekommt keinen Traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-Links Blog ↔ &lt;code&gt;/brokers&lt;/code&gt; ↔ Profile&lt;/td&gt;
&lt;td&gt;Partielle Autoritäts-Übertragung ohne Migration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;P1 — höchster SEO-Upside (Wochen 4–16)&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aktion&lt;/th&gt;
&lt;th&gt;Warum&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Near-Win-DE-Blogposts optimieren&lt;/td&gt;
&lt;td&gt;Schnellste Ranking-Wins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blog → &lt;code&gt;/blog/&lt;/code&gt;-Subfolder-Konsolidierung&lt;/td&gt;
&lt;td&gt;Größter struktureller Lift fürs Verzeichnis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pfad-Locales + &lt;code&gt;hreflang&lt;/code&gt; auf Apex&lt;/td&gt;
&lt;td&gt;Pflicht vor ES/EN-Skalierung&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DE-Pillar-Hub für grenzüberschreitendes Investment&lt;/td&gt;
&lt;td&gt;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;Spanische LatAm-Programmatic-Pages (CO/MX) erst, wenn Makler-Bestand mitspielt — leere City-Templates wären Thin-Content-Risiko.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;workflow-replizieren&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#workflow-replizieren&quot; aria-label=&quot;workflow replizieren permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Workflow replizieren&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SISTRIX MCP in Cursor verdrahten&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 oder API-Key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mit klarer Anfrage starten&lt;/strong&gt; — z. B. &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; (das war mein kompletter Start-Prompt).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-Market-Baseline anfragen&lt;/strong&gt; — &lt;code&gt;domain_visindex&lt;/code&gt; und &lt;code&gt;domain_kwcount_seo&lt;/code&gt; pro Land.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ranking-URLs ziehen&lt;/strong&gt; — &lt;code&gt;keyword_domain_seo&lt;/code&gt;, um zu sehen, welche Subdomain oder welcher Pfad wirklich rankt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chancen, Wettbewerber, 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;Codebase auditieren&lt;/strong&gt; — Canonicals, hreflang, robots, Sitemaps, i18n-Patterns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Synthetisieren&lt;/strong&gt; — Strategie-Doc mit priorisierten Stufen, kein Data-Dump.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;beispiel-deliverable-hallocasa-seo-strategie-pdf&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#beispiel-deliverable-hallocasa-seo-strategie-pdf&quot; aria-label=&quot;beispiel deliverable hallocasa seo strategie 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;Beispiel-Deliverable: HalloCasa SEO-Strategie (PDF)&lt;/h3&gt;
&lt;p&gt;Die Agent-Session lieferte ein vollständiges Strategie-Dokument — Baseline pro Markt, Wettbewerber-Overlap, technische Findings aus unserem Next.js-Repo und eine P0–P3-Roadmap. Als PDF für Stakeholder exportiert (&lt;code&gt;pandoc&lt;/code&gt; + headless Chrome aus dem 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-Strategie — Vorschau erste Seite&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;PDF herunterladen&lt;/a&gt; · &lt;a href=&quot;https://github.com/hallocasacom/hallocasa-next/blob/main/misc/seo/SEO_STRATEGY.md&quot;&gt;Markdown-Quelle&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ähnliches für deine Domain?&lt;/strong&gt; Ich helfe Teams, denselben SISTRIX-MCP- plus Codebase-Audit-Workflow zu fahren und daraus ein priorisiertes Strategie-Dokument zu machen. &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;takeaways-für-andere-sites&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#takeaways-f%C3%BCr-andere-sites&quot; aria-label=&quot;takeaways für andere 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 für andere Sites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP macht SEO von Dashboard-Archäologie zu agent-native Research.&lt;/strong&gt; Der Agent zieht Live-SISTRIX-Daten, während du im Editor bleibst.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Am besten, wenn der Agent auch dein Repo lesen kann.&lt;/strong&gt; Rankings sagen &lt;em&gt;was&lt;/em&gt; rankt; Code sagt &lt;em&gt;warum&lt;/em&gt; Fixes schwer oder leicht sind.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-Subdomain-Setups brauchen eine explizite Architektur-Entscheidung&lt;/strong&gt; — konsolidieren (z. B. Blog → &lt;code&gt;/blog/&lt;/code&gt;) oder stark verlinken; Autorität überträgt sich nicht von selbst.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Near-Win-Keywords priorisieren&lt;/strong&gt; vor Greenfield-Programmatic-SEO oder Neun-Locale-Übersetzungs-Marathons.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Marktdaten an Business-Fokus anpassen.&lt;/strong&gt; Kaum Sichtbarkeit in CO/MX trotz LatAm-Kerngeografie — die Diskrepanz sieht man nur bei Abfrage pro Land.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;was-als-nächstes-bei-hallocasa&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-als-n%C3%A4chstes-bei-hallocasa&quot; aria-label=&quot;was als nächstes bei 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;Was als Nächstes bei HalloCasa&lt;/h2&gt;
&lt;p&gt;Dieser Post geht um die &lt;strong&gt;Research-Methode&lt;/strong&gt; — aber das Audit lieferte eine klare Roadmap, und ich freue mich auf die Umsetzung: P0-Fixes zuerst, dann DE-Near-Win-Posts und Blog-Konsolidierung. SISTRIX bleibt für laufendes Tracking drin, nicht nur diese Session.&lt;/p&gt;
&lt;p&gt;Dasselbe MCP-Setup öffnet &lt;strong&gt;GEO&lt;/strong&gt; (Generative Engine Optimization): SISTRIX’ AI-Visibility-Tools (&lt;code&gt;ai_entity&lt;/code&gt; und verwandtes Project-Tooling) erlauben eine Baseline, wie HalloCasa in KI-Antworten auftaucht, und Messung des Lifts beim Fixen von Struktur und Content. Unser erster &lt;code&gt;ai_entity&lt;/code&gt;-Call lieferte 500 — Retry lohnt sich nach den Grundlagen.&lt;/p&gt;
&lt;p&gt;Ich bin Co-Founder von HalloCasa und nutze MCP auch sonst im Stack (siehe &lt;a href=&quot;/openclaw-de&quot;&gt;Wie ich OpenClaw nutze&lt;/a&gt; für einen anderen Blick auf Agent-Tooling). Wer Hilfe beim Verdrahten von SISTRIX MCP in Cursor oder ein ähnliches Audit auf der eigenen Domain will: &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88/&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Danke an &lt;a href=&quot;https://www.linkedin.com/in/benedikt-rudolf&quot;&gt;Benedikt Rudolf&lt;/a&gt; von SISTRIX, dass er sich die Zeit genommen hat, mir den MCP vorzustellen — dieses Gespräch hat den Workflow angestoßen.&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[Mit Lovable gebaut? Prod in Deutschland & DACH auf Hetzner hosten]]></title><description><![CDATA[Du hast mit Lovable gebaut — React-App, Supabase-Auth, Postgres. Es funktioniert. Dann fragt dein erster DACH-Kunde oder Pilot: Wo läuft…]]></description><link>https://martinmueller.dev/lovable-hetzner-germany-de/</link><guid isPermaLink="false">https://martinmueller.dev/lovable-hetzner-germany-de/</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[de]]></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;Du hast mit &lt;strong&gt;Lovable&lt;/strong&gt; gebaut — React-App, Supabase-Auth, Postgres. Es funktioniert. Dann fragt dein erster &lt;strong&gt;DACH&lt;/strong&gt;-Kunde oder Pilot: &lt;em&gt;Wo läuft Prod? Wo liegen Login und Daten?&lt;/em&gt; Die Frage kommt in &lt;strong&gt;Deutschland&lt;/strong&gt;, &lt;strong&gt;Österreich&lt;/strong&gt; und der &lt;strong&gt;Schweiz&lt;/strong&gt; im B2B schnell — besonders in HR, Health, Finance und allem, was Procurement oder ein Security-Fragebogen berührt.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;warum-eu-reicht-in-dach-oft-nicht-genug-ist&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#warum-eu-reicht-in-dach-oft-nicht-genug-ist&quot; aria-label=&quot;warum eu reicht in dach oft nicht genug ist permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Warum „EU reicht“ in DACH oft nicht genug ist&lt;/h2&gt;
&lt;p&gt;Lovables Standardweg — &lt;strong&gt;Netlify&lt;/strong&gt; (oder ähnlich) plus &lt;strong&gt;managed Supabase&lt;/strong&gt; — ist super zum Bauen. Für &lt;strong&gt;Prod, auf das du in einem Buyer-Review zeigen kannst&lt;/strong&gt;, reicht das nicht immer.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deutschland&lt;/strong&gt; — DSGVO, Vendor-Fragebögen, und „EU-Hosting“ heißt oft &lt;em&gt;benennbare EU-Infrastruktur&lt;/em&gt;, nicht „wir nutzen irgendwo eine US-Cloud in eu-west-1.“&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Österreich&lt;/strong&gt; — Gleicher DSGVO-Rahmen; viele Käufer spiegeln deutsche Erwartungen zu Datenstandort und Subprozessoren.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Schweiz&lt;/strong&gt; — Nicht in EU/DSGVO, aber starke Datenschutzerwartungen (revDSG). &lt;strong&gt;Hetzner&lt;/strong&gt; — deutsches Unternehmen, EU-Rechenzentren — ist für viele Schweizer Käufer eine glaubwürdige Antwort, ohne Compliance zu überverkaufen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Das ist keine Rechtsberatung. Es ist die praktische Reibung, wenn DACH-Kunden eine klare Antwort wollen, &lt;strong&gt;wo Prod läuft&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;phased-prod-auf-hetzner--dev-bleibt-auf-lovable&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#phased-prod-auf-hetzner--dev-bleibt-auf-lovable&quot; aria-label=&quot;phased prod auf hetzner  dev bleibt auf 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 auf Hetzner — Dev bleibt auf Lovable&lt;/h2&gt;
&lt;p&gt;Du brauchst &lt;strong&gt;keine Big-Bang-Migration&lt;/strong&gt;. In einer kürzlichen &lt;a href=&quot;/hetzner-eu-production-de&quot;&gt;Fallstudie mit deutschem Kunden&lt;/a&gt; blieb &lt;strong&gt;Dev&lt;/strong&gt; auf Netlify + managed Supabase, während &lt;strong&gt;Prod&lt;/strong&gt; — App, Login, Postgres — live auf &lt;strong&gt;Hetzner&lt;/strong&gt; in der EU ging. Gleiches Muster passt zu Lovable-Stacks: weiter in Lovable bauen; eine &lt;strong&gt;DACH-facing Prod-Umgebung&lt;/strong&gt; auf EU-VMs ergänzen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fallstudie:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/hetzner-eu-production-de&quot;&gt;Produktion auf Hetzner (Teil 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-de&quot;&gt;Self-hosted Insights (Teil 2)&lt;/a&gt; — Observability, Kosten-Guardrails, EU-Telemetrie&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prod-Nutzer treffen die React-App auf Hetzner. Sign-in und Postgres für Prod bleiben ebenfalls auf Hetzner. Dev nutzt Lovables Stack unverändert weiter.&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-Architektur auf Hetzner in der 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--kein-black-box-prod&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#open-source-stack--kein-black-box-prod&quot; aria-label=&quot;open source stack  kein 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 — kein Black-Box-Prod&lt;/h2&gt;
&lt;p&gt;DACH-Käufer fragen oft nicht nur &lt;em&gt;wo&lt;/em&gt; Daten liegen, sondern &lt;em&gt;welche Software dort läuft&lt;/em&gt;. Der Prod-Weg, den wir nutzen, baut auf &lt;strong&gt;Open Source&lt;/strong&gt;, die du benennen, prüfen und selbst betreiben kannst — kein proprietäres PaaS, das du nicht inspizieren kannst.&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 (ein Open-Source-Fork von 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 (von 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;Das zählt in Security Reviews: Subprozessoren und Komponenten sind identifizierbar. Du bist für Prod nicht in die Managed-Layer eines einzelnen Vendors eingesperrt. Hetzner liefert VMs; der Stack darauf bleibt portabel und forkbar.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;was-ich-übernehme-vs-was-du-weiter-machst&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-ich-%C3%BCbernehme-vs-was-du-weiter-machst&quot; aria-label=&quot;was ich übernehme vs was du weiter machst permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Was ich übernehme vs. was du weiter machst&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Du:&lt;/strong&gt; Features in Lovable weiter shippen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ich:&lt;/strong&gt; OpenTofu (Server, Firewall, DNS), GitHub-Actions-Deploys, &lt;strong&gt;self-hosted Open-Source-Supabase&lt;/strong&gt; auf Prod-VMs und &lt;strong&gt;self-hosted Observability&lt;/strong&gt; (Grafana LGTM, Kosten-Alerts) — die Dokumentation, die DACH-Käufer oft fragen: wo Daten liegen, was dort läuft, wer Prod betreibt, was es kostet.&lt;/p&gt;
&lt;p&gt;Ich arbeite mit &lt;strong&gt;DACH-Kunden&lt;/strong&gt; genau auf diesem Pfad. Wenn das dein nächster Schritt klingt, melde dich.&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;weiterlesen&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#weiterlesen&quot; aria-label=&quot;weiterlesen permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Weiterlesen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/hetzner-eu-production-de&quot;&gt;Produktion auf Hetzner für einen deutschen Kunden (Teil 1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/hetzner-self-hosted-insights-de&quot;&gt;Self-hosted Insights auf Hetzner (Teil 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[Produktion auf Hetzner für einen deutschen Kunden — EU-Hosting (Teil 1)]]></title><description><![CDATA[Teil 2: Self-hosted Insights auf Hetzner Ein deutscher Kunde brauchte Produktion in der EU auf Hetzner — klare Kontrolle darüber, wo…]]></description><link>https://martinmueller.dev/hetzner-eu-production-de/</link><guid isPermaLink="false">https://martinmueller.dev/hetzner-eu-production-de/</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[de]]></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;Teil 2:&lt;/strong&gt; &lt;a href=&quot;/hetzner-self-hosted-insights-de&quot;&gt;Self-hosted Insights auf Hetzner&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ein &lt;strong&gt;deutscher Kunde&lt;/strong&gt; brauchte &lt;strong&gt;Produktion in der EU auf Hetzner&lt;/strong&gt; — klare Kontrolle darüber, wo Kundendaten und Login liegen. Das Produkt ist &lt;strong&gt;Arc Rider Universe&lt;/strong&gt;: die SaaS hinter &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;, ein UI-Toolkit für Builder (Tabellen, Kanban, Gantt, Layouts und mehr per JSON statt handgeschriebener UI-Code). &lt;strong&gt;Dev&lt;/strong&gt; lief bereits problemlos auf &lt;strong&gt;Netlify&lt;/strong&gt; und &lt;strong&gt;managed Supabase&lt;/strong&gt; — und tut das weiterhin. Ziel war eine &lt;strong&gt;dedizierte Prod-Umgebung auf Hetzner&lt;/strong&gt;, keine Big-Bang-Migration, die das Team ausbremst.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;warum-hetzner-und-warum-nicht-alles-auf-einmal-umziehen&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#warum-hetzner-und-warum-nicht-alles-auf-einmal-umziehen&quot; aria-label=&quot;warum hetzner und warum nicht alles auf einmal umziehen permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Warum Hetzner, und warum nicht „alles auf einmal umziehen“&lt;/h2&gt;
&lt;p&gt;Der Kunde sitzt in Deutschland. &lt;strong&gt;Prod&lt;/strong&gt; musste auf &lt;strong&gt;EU-Infrastruktur&lt;/strong&gt;, auf die er verweisen kann — Hetzner-VMs für App und Datenbank.&lt;/p&gt;
&lt;p&gt;Das hieß &lt;strong&gt;nicht&lt;/strong&gt;, Dev anzufassen:&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) bleibt auf &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 — läuft auf &lt;strong&gt;Hetzner&lt;/strong&gt; unter &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;Wenn du Ähnliches planst: EU-Prod auf Hetzner geht &lt;strong&gt;an einem Wochenende&lt;/strong&gt; — &lt;strong&gt;ohne&lt;/strong&gt; Dev umzuplatformen.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;wie-prod-aussieht-kurz-erklärt&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wie-prod-aussieht-kurz-erkl%C3%A4rt&quot; aria-label=&quot;wie prod aussieht kurz erklärt permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wie Prod aussieht (kurz erklärt)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Prod-Nutzer&lt;/strong&gt; öffnen die React-App auf Hetzner. Anmeldung und Daten für Prod liegen ebenfalls auf Hetzner. Dev nutzt weiter Netlify und managed Supabase unverändert.&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-Architektur auf 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 und Deploys sind automatisiert mit &lt;strong&gt;OpenTofu&lt;/strong&gt; (Server, Firewall, DNS) und &lt;strong&gt;GitHub Actions&lt;/strong&gt; (Build, Deploy, kurze Smoke-Checks nach einem Release).&lt;/p&gt;
&lt;p&gt;Sobald Prod stabil war, kam &lt;strong&gt;self-hosted Observability&lt;/strong&gt; auf einer dedizierten VM dazu — Metriken, Logs, Traces, Kosten-Wächter und agentenfreundlicher Betrieb. Siehe &lt;a href=&quot;/hetzner-self-hosted-insights-de&quot;&gt;Teil 2&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;was-wir-gelernt-haben-kurzfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-wir-gelernt-haben-kurzfassung&quot; aria-label=&quot;was wir gelernt haben kurzfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Was wir gelernt haben (Kurzfassung)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phasenweise schlägt Big Bang&lt;/strong&gt; — Dev blieb auf Netlify + managed Supabase, während Hetzner-Prod live ging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-hosted Login ist kein Copy-Paste aus Cloud-Supabase&lt;/strong&gt; — Prod-OAuth und Magic Links brauchen prod-spezifische URLs und Config; Dev-Config bleibt getrennt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Planbare Kosten und EU-Hosting&lt;/strong&gt; — VMs auf Hetzner für App, Login und Daten.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prod ist live unter &lt;a href=&quot;https://universe.arc-rider.com&quot;&gt;universe.arc-rider.com&lt;/a&gt;. Für diese Produktphase hat der Tradeoff gepasst: &lt;strong&gt;Kontrolle dort, wo es zählt&lt;/strong&gt; — auf EU-Infrastruktur, auf die der Kunde verweisen kann.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;hetzner-migrationen--wie-ich-helfen-kann&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hetzner-migrationen--wie-ich-helfen-kann&quot; aria-label=&quot;hetzner migrationen  wie ich helfen kann permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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-Migrationen — wie ich helfen kann&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Netlify&lt;/strong&gt;, &lt;strong&gt;managed Supabase&lt;/strong&gt; oder &lt;strong&gt;AWS&lt;/strong&gt; für Dev und &lt;strong&gt;Prod in der EU auf Hetzner&lt;/strong&gt; nötig? Ich helfe bei Planung, OpenTofu, CI-Deploys, self-hosted Supabase auf Prod-VMs und &lt;strong&gt;self-hosted Observability&lt;/strong&gt; (Grafana LGTM, Alloy, Kosten-Wächter, Grafana MCP für agentenfreundlichen Betrieb).&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;weiterführende-links&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#weiterf%C3%BChrende-links&quot; aria-label=&quot;weiterführende links permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Weiterführende Links&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 als 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 auf Hetzner — Observability, Kosten, KI-Agenten (Teil 2)]]></title><description><![CDATA[Teil 1: EU-Produktion auf Hetzner Nachdem Prod auf Hetzner live ging — React-App, self-hosted Supabase-Login, Postgres auf EU-VMs; Dev…]]></description><link>https://martinmueller.dev/hetzner-self-hosted-insights-de/</link><guid isPermaLink="false">https://martinmueller.dev/hetzner-self-hosted-insights-de/</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[de]]></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;Teil 1:&lt;/strong&gt; &lt;a href=&quot;/hetzner-eu-production-de&quot;&gt;EU-Produktion auf Hetzner&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nachdem &lt;a href=&quot;/hetzner-eu-production-de&quot;&gt;Prod auf Hetzner live ging&lt;/a&gt; — React-App, self-hosted Supabase-Login, Postgres auf EU-VMs; Dev weiter auf Netlify + managed Supabase — kam &lt;strong&gt;self-hosted Observability&lt;/strong&gt; auf einer dedizierten Prod-VM dazu. Metriken, Logs, Traces und Kostendaten bleiben in der EU. Kein APM-SaaS von Drittanbietern. Danach haben wir &lt;strong&gt;KI-Agenten&lt;/strong&gt; angebunden, die Prod über Grafana MCP abfragen — statt SSH-Rätselraten.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;insights-ohne-die-eu-zu-verlassen&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#insights-ohne-die-eu-zu-verlassen&quot; aria-label=&quot;insights ohne die eu zu verlassen permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 ohne die EU zu verlassen&lt;/h2&gt;
&lt;p&gt;Wir haben &lt;strong&gt;self-hosted Observability&lt;/strong&gt; auf Hetzner ergänzt: OpenTelemetry-Ingest, &lt;strong&gt;Grafana LGTM&lt;/strong&gt; (Prometheus, Loki, Tempo) und &lt;strong&gt;Grafana-Alloy&lt;/strong&gt;-Agenten auf den Static- und Supabase-VMs. Browser-&lt;strong&gt;RUM&lt;/strong&gt; sowie Edge-Function-Traces und -Logs exportieren in denselben Stack — nichts verlässt die EU für die Frage „wie läuft Prod?“&lt;/p&gt;
&lt;p&gt;Provisionierte 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;Was es zeigt&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;Fließen Metriken, Logs und Traces?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prod Overview&lt;/td&gt;
&lt;td&gt;Prod-Gesundheit auf einen Blick&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure USE&lt;/td&gt;
&lt;td&gt;CPU, RAM, Disk auf den VMs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nginx RED&lt;/td&gt;
&lt;td&gt;Request-Rate, Fehler, Dauer aus 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 auf der API-VM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Postgres&lt;/td&gt;
&lt;td&gt;Verbindungen, 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;Warum das für Kunden zählt:&lt;/strong&gt; Datadog-Klasse Sichtbarkeit, ohne Telemetrie an US-SaaS zu schicken oder per SSH zu raten. Dashboards und Alert-Regeln liegen in Git; Google OAuth schützt die Grafana-UI.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;planbare-kosten-automatisch-im-blick&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#planbare-kosten-automatisch-im-blick&quot; aria-label=&quot;planbare kosten automatisch im blick permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Planbare Kosten, automatisch im Blick&lt;/h2&gt;
&lt;p&gt;Hetzner-Preise sind transparent — aber drei VMs, Backups, Primary IPs und Volumes summieren sich. Wir haben ein &lt;strong&gt;Production Costs&lt;/strong&gt;-Dashboard angebunden, das &lt;strong&gt;live Hetzner-API-Preise&lt;/strong&gt; in Prometheus zieht (&lt;code&gt;arc_infra_cost_eur_monthly&lt;/code&gt;): Aufschlüsselung pro Server, Backup, Volume und Primary IP, plus monatliche und jährliche Projektion.&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 auf 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;Ein &lt;strong&gt;Grafana-Alert&lt;/strong&gt; feuert, wenn die geschätzte Infra-Kosten &lt;strong&gt;50 EUR/Monat&lt;/strong&gt; erreichen — E-Mail an die Ops-Liste, bevor die Rechnung überrascht. Das Gegenteil von undurchsichtigen Cloud-Rechnungen, bei denen man den Spike erst in der Console entdeckt.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ki-agenten-mit-echten-tools&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ki-agenten-mit-echten-tools&quot; aria-label=&quot;ki agenten mit echten 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;KI-Agenten mit echten Tools&lt;/h2&gt;
&lt;p&gt;Vieles wurde mit &lt;strong&gt;KI-Assistenten im Loop&lt;/strong&gt; designed, debuggt und &lt;strong&gt;betrieben&lt;/strong&gt; (Cursor, Claude Code). Die wichtigste Erkenntnis: Sobald Grafana self-hosted auf Hetzner läuft, kann man Agenten auf &lt;strong&gt;Prod selbst&lt;/strong&gt; zeigen — nicht nur auf Docs und IaC.&lt;/p&gt;
&lt;p&gt;Mit &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;) und einem &lt;strong&gt;read-only Viewer&lt;/strong&gt;-Service-Account-Token kann ein Agent:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PromQL&lt;/strong&gt; ausführen (Host-CPU, Postgres-Verbindungen, Kosten-Metriken)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LogQL&lt;/strong&gt; ausführen (nginx-Access-Logs, Edge-Function-Output)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dashboards suchen&lt;/strong&gt; und Panels zusammenfassen&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alert-Regeln listen&lt;/strong&gt; und Firing-Status prüfen&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Das machte aus „etwas ist langsam in Prod“ einen Loop: Agent fragt Grafana ab → findet Panel oder Log-Stream → schlägt Fix in Git/CI vor oder wendet ihn an — ohne SSH-Rätselraten. &lt;strong&gt;Tool-Freigabe bleibt an&lt;/strong&gt; in Cursor; Token ist read-only; Infra- und Schema-Änderungen laufen weiter über OpenTofu und CI.&lt;/p&gt;
&lt;p&gt;Unter &lt;strong&gt;Cursor → Settings → Tools &amp;#x26; MCP&lt;/strong&gt; verdrahtet das Projekt MCP-Server plus die üblichen CLIs:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Wofür wir es nutzen&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;Server, IPs, Firewalls vom Terminal prüfen&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;Infra planen und anwenden (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;Provider-Docs im Chat nachschlagen (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;Migrationen und Schema-Arbeit 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;offizielles hosted MCP&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;Tabellen inspizieren, read-only SQL, Logs und 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 auf 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;Zusammen mit Runbooks fühlte sich das näher an &lt;strong&gt;IaC plus Observability plus CLIs&lt;/strong&gt; als an „SSH auf einen Pet-Server und hoffen“. Applies laufen weiter über OpenTofu/CI; MCP ist für Lookup, Schema, Logs und Prod-Queries — keine stillen Infra- oder Schema-Writes.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;was-wir-gelernt-haben-kurzfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-wir-gelernt-haben-kurzfassung&quot; aria-label=&quot;was wir gelernt haben kurzfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Was wir gelernt haben (Kurzfassung)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Observability auf Hetzner ist ein Produkt-Asset&lt;/strong&gt; — Metriken, Logs und Traces in der EU, aus Git provisioniert, kein APM-SaaS-Lock-in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Planbare Kosten und EU-Hosting&lt;/strong&gt; — Kosten-Dashboard + Budget-Alert, damit Ausgaben sichtbar bleiben, bevor die Rechnung überrascht.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KI-Agenten glänzen auf self-hosted Grafana&lt;/strong&gt; — Grafana MCP + read-only Token lässt Agenten Prod untersuchen (PromQL, LogQL, Dashboards) statt per SSH zu raten.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prod ist live unter &lt;a href=&quot;https://prod.universe.arc-rider.com&quot;&gt;prod.universe.arc-rider.com&lt;/a&gt;. Für diese Produktphase hat der Tradeoff gepasst: &lt;strong&gt;Kontrolle dort, wo es zählt&lt;/strong&gt; — auf EU-Infrastruktur, auf die der Kunde verweisen kann, inklusive wie Prod überwacht wird und was es kostet.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;hetzner-migrationen--wie-ich-helfen-kann&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hetzner-migrationen--wie-ich-helfen-kann&quot; aria-label=&quot;hetzner migrationen  wie ich helfen kann permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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-Migrationen — wie ich helfen kann&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Netlify&lt;/strong&gt;, &lt;strong&gt;managed Supabase&lt;/strong&gt; oder &lt;strong&gt;AWS&lt;/strong&gt; für Dev und &lt;strong&gt;Prod in der EU auf Hetzner&lt;/strong&gt; nötig? Ich helfe bei Planung, OpenTofu, CI-Deploys, self-hosted Supabase auf Prod-VMs und &lt;strong&gt;self-hosted Observability&lt;/strong&gt; (Grafana LGTM, Alloy, Kosten-Wächter, Grafana MCP für agentenfreundlichen Betrieb).&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;weiterführende-links&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#weiterf%C3%BChrende-links&quot; aria-label=&quot;weiterführende links permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Weiterführende Links&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[AI Softwareentwicklung mit Ninox und arcBot]]></title><description><![CDATA[KI beflügelt die Unternehmenslandschaft. Viele einfache und komplexe Prozesse im Unternehmen können durch AI stark vereinfacht oder sogar…]]></description><link>https://martinmueller.dev/arcbot/</link><guid isPermaLink="false">https://martinmueller.dev/arcbot/</guid><category><![CDATA[de]]></category><category><![CDATA[2024]]></category><category><![CDATA[ninox]]></category><category><![CDATA[ai]]></category><pubDate>Wed, 14 Feb 2024 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/9c11b79bf80e850adca158f53ffa3e5a/titleEngineerRobot.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;KI beflügelt die Unternehmenslandschaft. Viele einfache und komplexe Prozesse im Unternehmen können durch AI stark vereinfacht oder sogar komplett automatisiert werden. Jakob mein Co-Founder und ich sehen es als spannende Herausforderung, wie wir den Zugang zu AI für kleine und mittelständische Unternehmen vereinfachen können. Wir glauben mit der Low Code Plattform &lt;a href=&quot;https://ninox.com&quot;&gt;Ninox&lt;/a&gt; und unserem AI Chatbot &lt;a href=&quot;https://app.arcbot.de&quot;&gt;arcBot&lt;/a&gt; einen spannenden Ansatz gefunden zu haben. In diesem Blogpost möchte ich euch diesen Ansatz vorstellen.&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; ist eine cloudbasierte Low-Code-Plattform zum Bau von Softwarelösungen für kleine und mittelständische Unternehmen. Ninox wurde 2013 in Deutschland von &lt;a href=&quot;https://www.linkedin.com/in/frank-boehmer/&quot;&gt;Frank Böhmer&lt;/a&gt; gegründet. Hier einige Möglichkeiten, wie Ninox Unternehmen unterstützen kann:&lt;/p&gt;
&lt;p&gt;Automatisierung der Geschäftsprozesse: Mit Ninox können Unternehmen ihre täglichen Aufgaben und Prozesse automatisieren und so ihre Effizienz steigern.&lt;/p&gt;
&lt;p&gt;Anpassbarkeit: Da Ninox eine Low-Code-Plattform ist, können Unternehmen ihre Anwendungen ohne komplexe Programmierkenntnisse an ihre spezifischen Bedürfnisse anpassen.&lt;/p&gt;
&lt;p&gt;Integration: Ninox kann mit einer Vielzahl anderer Tools und Plattformen integriert werden, was einen nahtlosen Datenaustausch zwischen verschiedenen Systemen ermöglicht.&lt;/p&gt;
&lt;p&gt;Kosteneffizienz: Verglichen mit der Entwicklung einer benutzerdefinierten Software von Grund auf, kann die Verwendung einer Low-Code-Plattform wie Ninox zu erheblichen Kosteneinsparungen führen.&lt;/p&gt;
&lt;p&gt;Schnelle Implementierung: Mit Ninox können Unternehmen ihre Anwendungen schnell erstellen und implementieren, was zu einer schnelleren Markteinführung führt.&lt;/p&gt;
&lt;p&gt;Vor einigen Monaten habe ich mit Ninox ein MVP erstellt. Meine gesammelten Erfahrungen können &lt;a href=&quot;https://martinmueller.dev/ninox-mvp&quot;&gt;hier&lt;/a&gt; nachgelesen werden. Im nächsten Kapitel erkläre ich, wie wir mit arcBot den Build für deine Softwarelösung in ninox vereinfachen.&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;Der arcBot ist eine ChatGPT-ähnliche KI zum schnellen Erstellen und Modifizieren von Ninox-Tabellen. Wir benutzen die AWS Bedrock API um die Ninox Tabellen Antworten zu erstellen. Ein Beispiel Prompt zum erstellen von Ninox Tabellen könnte wie folgt aussehen:&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;Zeichnung&quot; width=&quot;800&quot;&gt;
&lt;p&gt;Cool oder? arcBot erstellt viele Tabellen für Kunden und Produkte. Bemerkenswert ist, dass arcBot sogar die ninox-typischen inversen Felder setzen kann. Im nächsten Prompt wollen wir den Last Name zu einem Customer hinzufügen.&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;Für die Antwort verwendet arcBot das &lt;a href=&quot;https://docs.anthropic.com/claude/docs/claude-2p1-guide&quot;&gt;Claude v2.1 model&lt;/a&gt;, das über die &lt;a href=&quot;https://docs.aws.amazon.com/bedrock/&quot;&gt;AWS Bedrock API&lt;/a&gt; zur Verfügung gestellt wird.&lt;/p&gt;
&lt;p&gt;Wie stellen wir sicher, dass die Qualität der Antworten so hoch wie möglich ist? Wir haben eine Feedbackschleife eingebaut. Der Nutzer kann nach der Antwort Feedback geben. Dieses Feedback wird dann zur Verbesserung von arcBot verwendet.&lt;/p&gt;
&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/arcbot/feedback1.png&quot; alt=&quot;Zeichnung&quot; width=&quot;800&quot;&gt;
&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/arcbot/feedback2.png&quot; alt=&quot;Zeichnung&quot; width=&quot;800&quot;&gt;
&lt;p&gt;Ich stehe auch in engem Kontakt mit anderen Gen AI Experten, die mir helfen, die Qualität der arcBot Antworten zu verbessern. An dieser Stelle möchte ich mich bei diesen Experten bedanken. Es sind hauptsächlich AWS Community Mitglieder und AWS Mitarbeiter die mir schon viele wertvolle Tipps gegeben haben. Vielen Dank 🙏&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;Es ist cool, dass wir mit arcBot Ninox Tabellen erstellen können, aber wie können wir die Daten in Ninox weiterverarbeiten? Hier kommt der Ninox Connector ins Spiel. Der Ninox Connector kann Ninox Tabellen lesen und aktualisieren. Das folgende Bild zeigt den 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;Zeichnung&quot; width=&quot;800&quot;&gt;.&lt;/p&gt;
&lt;p&gt;Der Ninox Connector benötigt einige Informationen wie die Ninox Url, Team Id, Database Id und den Ninox API Key. Zurzeit is der Ninox Connector nur über den Early Access verfügbar. Dieser ist aber ganz leicht auf &lt;a href=&quot;https://app.arcbot.de/&quot;&gt;https://app.arcbot.de/&lt;/a&gt; zu bekommen.&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;Werdet Teil unserer &lt;a href=&quot;https://discord.gg/MMWZSHSrEQ&quot;&gt;Discord Community&lt;/a&gt;. Wir haben bereits einige Member welche uns wertvolles Feedback und Feature Wünsche zu dem arcBot mitteilen.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;In diesem Blogpost habe ich euch gezeigt, wie wir durch die Kombination von Ninox und arcBot das Erstellen und Aktualisieren von Ninox-Tabellen vereinfachen. Wir freuen uns auf euer Feedback. Vielen Dank fürs Lesen.&lt;/p&gt;
&lt;p&gt;Ich liebe es, an Open-Source-Projekten zu arbeiten. Viele Dinge kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt;. Wenn du meine Arbeit dort und meine Blog-Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen:&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;Oder&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;Und schau doch mal auf meiner Seite vorbei&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/9c11b79bf80e850adca158f53ffa3e5a/titleEngineerRobot.png</featuredImage><media:content url="https://martinmueller.dev/static/9c11b79bf80e850adca158f53ffa3e5a/titleEngineerRobot.png" medium="image"/></item><item><title><![CDATA[AWS User Group (UG) Meetups organisieren]]></title><description><![CDATA[AWS UG Meetups sind eine tolle Möglichkeit um sich mit anderen AWS Enthusiasten auszutauschen. Ich zeige dir wie ich das AWS UG Lisbon…]]></description><link>https://martinmueller.dev/aws-ug/</link><guid isPermaLink="false">https://martinmueller.dev/aws-ug/</guid><category><![CDATA[de]]></category><category><![CDATA[2023]]></category><category><![CDATA[aws]]></category><category><![CDATA[social]]></category><pubDate>Fri, 09 Jun 2023 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/fddeabeb894b4ec6f0bc2eb7fa245842/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;AWS UG Meetups sind eine tolle Möglichkeit um sich mit anderen AWS Enthusiasten auszutauschen. Ich zeige dir wie ich das AWS UG Lisbon Meetup organisiert habe.&lt;/p&gt;
&lt;h2 id=&quot;vorgeschichte&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#vorgeschichte&quot; aria-label=&quot;vorgeschichte permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Vorgeschichte&lt;/h2&gt;
&lt;p&gt;Anfang 2023 sind wir von Deutschland nach Lissabon in Portugal umgezogen. Mit Entsetzen habe ich festgestellt, dass es keine AWS Meetup Events in Lissabon gibt. Also habe ich mich entschieden die Organisierer des AWS UG Meetup anzuschreiben und meine Hilfe anzubieten. Die wurde dankend angenommen und ich bin seit Anfang des Jahres 2023 ein Co-Organisierer des AWS UG Lisbon Meetup.&lt;/p&gt;
&lt;h2 id=&quot;mein-erstes-meetup-als-organisierer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#mein-erstes-meetup-als-organisierer&quot; aria-label=&quot;mein erstes meetup als organisierer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Mein erstes Meetup als Organisierer&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Ich zeige wie ich das AWS UG Lisbon Meetup organisiert habe&lt;/li&gt;
&lt;li&gt;Seit Anfang des Jahres 2023 bin ich ein Co-Organisierer des AWS UG Lisbon Meetup.&lt;/li&gt;
&lt;li&gt;Nutze Meetup.com zur Bekanntmachung des Meetup Event. Selbst wenn wir die Speakers noch nicht bestimmt haben.&lt;/li&gt;
&lt;li&gt;Nutze Google Forms zum sammeln der Speaker Talks&lt;/li&gt;
&lt;li&gt;Meetup Organisierer voten dann welchen Tag sie gerne hören würden&lt;/li&gt;
&lt;/ul&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;ul&gt;
&lt;li&gt;Wie können wir die Meetup Erfahrung verbessern&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;h2 id=&quot;outlook-1&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#outlook-1&quot; aria-label=&quot;outlook 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;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 Indexieren mit Chatsindex.com]]></title><description><![CDATA[Möchtest du deine Chat Community vergrößern? Chatsindex.com indexiert Chat-Messages und macht diese auffindbar für Suchmaschinen wie Google…]]></description><link>https://martinmueller.dev/chatsindex/</link><guid isPermaLink="false">https://martinmueller.dev/chatsindex/</guid><category><![CDATA[de]]></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;Möchtest du deine Chat Community vergrößern? &lt;a href=&quot;https://Chatsindex.com&quot;&gt;Chatsindex.com&lt;/a&gt; indexiert Chat-Messages und macht diese auffindbar für Suchmaschinen wie Google. Zugegeben es wird das machen weil es zurzeit noch ein Prototype ist! Durch SEO (Search Engine Optimization) wird sichergestellt, dass die Einträge möglichst hoch in den Suchergebnissen erscheinen. So können neue User auf deinen Discord Server gelockt werden.&lt;/p&gt;
&lt;p&gt;Nachfolgend siehst du ein Beispiel wie ein Discord Channel und die Suchergebnisse aussehen können:&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;Die Google Seite ist dabei nur gemocked (&lt;a href=&quot;https://Chatsindex.com/search&quot;&gt;Chatsindex.com/search&lt;/a&gt;) da es sich noch um einen Prototypen handelt.&lt;/p&gt;
&lt;h2 id=&quot;wie-funktioniert-es&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wie-funktioniert-es&quot; aria-label=&quot;wie funktioniert es permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wie funktioniert es?&lt;/h2&gt;
&lt;p&gt;Ein Discord Bot schreibt die Nachrichten in eine Datenbank. Die Datenbank wird dann von einem NextJS Server abgefragt und in eine Suchmaschinen optimierte Seite (SEO) gerendert. Die Seite wird dann von Google gecrawlt und die Einträge sind dann auffindbar.&lt;/p&gt;
&lt;p&gt;Der Prototyp ist mit dem &lt;a href=&quot;https://martinmueller.dev/t3-stack&quot;&gt;T3 Stack&lt;/a&gt; erstellt. Der T3 Stack ist ein NextJS Stack mit TailwindCSS, tRPC und Prisma. Die Datenbank besteht zurzeit noch aus SQLite und wird mit tRPC und Prisma abgefragt. Die Seite wird mit NextJS und TailwindCSS gerendert.&lt;/p&gt;
&lt;h2 id=&quot;probanden&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#probanden&quot; aria-label=&quot;probanden permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Probanden&lt;/h2&gt;
&lt;p&gt;Klingt diese Idee interessant für dich? Dann melde dich gerne bei mir &lt;a href=&quot;https://MartinMueller.dev&quot;&gt;https://MartinMueller.dev&lt;/a&gt;. Ich suche Probanden mit Discord Servern um die Idee zu testen.&lt;/p&gt;
&lt;h2 id=&quot;ausblick&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ausblick&quot; aria-label=&quot;ausblick permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ausblick&lt;/h2&gt;
&lt;p&gt;Falls die Idee gut ankommt, möchte ich gerne andere private Chatsysteme wie WhatsApp Gruppen, Telegram Gruppen, Slack, etc. indexieren.&lt;/p&gt;
&lt;p&gt;Eine weitere Idee von mir ist eine übergreifende Suche für private Chats wie Discord, WhatsApp Gruppen, Telegram Gruppen und Slack zu implementieren. Mit bestimmten Schlagwörtern oder Kategorien können dann private Chats mit bestimmten Themeninhalten gefunden werden. Zum Beispiel wenn ich mich für finanzielle Bildung interessiere, kann ich dann einfach in der Suche Finanzen eingeben und es werden mir Discord Server, WhatsApp/Telegram Gruppen usw. mit dem Themenschwerpunkt Finanzen vorgestellt. Wenn euch die Idee gefällt, wendet euch gerne an mich.&lt;/p&gt;
&lt;h2 id=&quot;fazit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fazit&quot; aria-label=&quot;fazit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fazit&lt;/h2&gt;
&lt;p&gt;Die Kombination aus SEO und Discord Servern empfinde ich als eine spannende Idee. Jetzt geht es mir erstmal darum die Idee zu testen und zu schauen ob es überhaupt eine Nachfrage gibt. Falls du Interesse hast, melde dich gerne bei mir.&lt;/p&gt;
&lt;p&gt;Den &lt;a href=&quot;https://martinmueller.dev/t3-stack&quot;&gt;T3 Stack&lt;/a&gt; zu verwenden hat viel Spaß gemacht und ich habe nur ein Wochenende benötigt für diesen Prototypen. Falls du Hilfe bei deiner Idee oder Projekten braucht, kontaktiere mich gerne.&lt;/p&gt;
&lt;p&gt;Ich liebe es, an Open-Source-Projekten zu arbeiten. Viele Dinge kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt;. Wenn du meine Arbeit dort und meine Blog-Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen:&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;Oder&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;Und schau doch mal auf meiner Seite vorbei&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/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, Mit Amplify AppSync ist es möglich mit deklarativem Code ein AWS AppSync zu konfigurieren. Mit Directives wie @model, @auth oder…]]></description><link>https://martinmueller.dev/amplify-permission/</link><guid isPermaLink="false">https://martinmueller.dev/amplify-permission/</guid><category><![CDATA[de]]></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;Mit Amplify AppSync ist es möglich mit deklarativem Code ein AWS AppSync zu konfigurieren. Mit &lt;a href=&quot;https://docs.amplify.aws/cli-legacy/graphql-transformer/directives/&quot;&gt;Directives&lt;/a&gt; wie &lt;strong&gt;@model&lt;/strong&gt;, &lt;strong&gt;@auth&lt;/strong&gt; oder &lt;strong&gt;@function&lt;/strong&gt; können andere AWS Services wie DynamoDB, Cognito oder Lambda sinnvoll mit AppSync verbunden werden. Das macht es einem mächtigen Werkzeug. Mit nur wenigen Zeilen GraphQL Code kann quasi schon sehr viel in AWS konfiguriert werden.&lt;/p&gt;
&lt;p&gt;Nachfolgend siehst du ein Amplify AppSync Beispiel:&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;Hier passiert eine ganze Menge! Mit der @model Directive wird automatisch eine DynamoDB Tabelle mit dem Namen User erzeugt welche die User Einträge als DynamoDB Items speichert. Mit @key wird die email als PK (Partition Key) festgelegt. Die Permission, wer also auf die Items zugreifen darf, wird mit @auth definiert. Ein User in der Admin Group darf also alle Items querien, mutieren und subscriben.&lt;/p&gt;
&lt;p&gt;Mit { allow: private, provider: iam } darf eine IAM Entität welche die erforderlichen Permissions besitzt ebenfalls die Items querien, mutieren und subscriben. Das verwende ich zum Beispiel bei Lambdas die bestimmte Aufgaben durchführen sollen wie dem Erstellen von neuen Usern in der Tabelle wenn sich diese zum ersten mal via Cognito anmelden.&lt;/p&gt;
&lt;p&gt;Zu guter Letzt mit { allow: owner, ownerField: &quot;email&quot;, identityClaim: &quot;email&quot; } dürfen Cognito User, welche sich über oauth2 identifiziert haben auf ihre Items zugreifen. Der identity claim email wird dabei über das Cognito JWT Token mitgeliefert und wird anschliessend mit der im Item definierten email abgeglichen.&lt;/p&gt;
&lt;p&gt;Ziemlich cool oder? Mir nur diesen wenigen Zeilen Amplify AppSync GraphQL Code bekommen wir sehr viel Funktionalität.&lt;/p&gt;
&lt;h2 id=&quot;permission-für-shared-items&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#permission-f%C3%BCr-shared-items&quot; aria-label=&quot;permission für 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 für Shared Items&lt;/h2&gt;
&lt;p&gt;Die Permission zu definieren mit @auth funktioniert sehr gut für einfache Fälle wie dem hier gezeigtem User Beispiel. Aber was ist wenn auf Items von mehreren Benutzern zugegriffen werden soll? Nun hier gibt es verschiedene Möglichkeiten die ich vorstellen möchte. Aber zuerst stelle ich die Tabelle mit den gemeinsam genutzten Items vor:&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;projektNummer&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;Ein Project soll für mehrere User zugreifbar sein. Der wohl einfachste Ansatz wäre die User in einer String-List zu speichern.&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;Der Code muss dafür nur minimal angepasst werden mit:&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;projektNummer&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;Die userEmails String-List muss nun einfach nur mit den emails von den Usern, die darauf zugreifen können, aktuell gehalten werden. Das Verwalten der userEmails ist aber aufwendig und erfordert zusätzlichen code und Platz im Item.&lt;/p&gt;
&lt;h2 id=&quot;virtuelle-lambda&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#virtuelle-lambda&quot; aria-label=&quot;virtuelle 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;Virtuelle Lambda&lt;/h2&gt;
&lt;p&gt;Wir könnten aber auch eine virtuelle Lambda benutzen welche dynamisch berechnet ob der jeweilige User Zugriff haben soll oder nicht.&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;projektNummer&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;Die Lösung besticht durch den reduzierten Platz in der DynamoDB Tabelle. Bei einer grossen Menge an Items würde es aber eine grosse Anzahl an Lambda-Aufrufen bedeuten welche die Kosten in die Höhe treiben. Auch kann der Delay durch den Lambda-Aufruf zu signifikant sein.&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;Diese Idee ist wohl die Kreativste. Über den pre-token-generation Trigger Lambda kann ein claim gesetzt werden welcher signalisiert, auf welches Item zugegriffen werden darf. Der Code für Amplify AppSync sieht in etwa so aus:&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;projektNummer&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;Der Identity-Claim &lt;strong&gt;currentProjectId&lt;/strong&gt; wird durch den pre-token-generation Trigger Lambda gesetzt. Diese Methode finde ich am elegantesten und verwende diese in meinen Projekten.&lt;/p&gt;
&lt;p&gt;Der Code für die Lambda könnte in etwa so aussehen:&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;Die Lambda ermittelt zuerst auf welches Project der User zugreifen darf mit &lt;strong&gt;currentProjectId&lt;/strong&gt; und dann setzt sie das Claim &lt;code&gt;currentProjectId:1234&lt;/code&gt;. Nun muss natürlich noch implementiert werden wie der User die currentProjectId überhaupt wechseln bzw. setzen kann und wie anschliessend das JWT Token neu geladen wird.&lt;/p&gt;
&lt;p&gt;Bei mir passiert dass wenn der User über den React Router auf das Project klickt. Zuerst wird der currentProjectId Eintrag in der User Tabelle getätigt und dann wird mittels des JWT Refresh Tokens das JWT Token neu geladen. Wenn ihr das gerne im Detail haben möchtet, dann schreibt mir.&lt;/p&gt;
&lt;h2 id=&quot;fazit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fazit&quot; aria-label=&quot;fazit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fazit&lt;/h2&gt;
&lt;p&gt;Ich habe hier unterschiedliche Methoden vorgestellt wie Permissions mit der Amplify AppSync directive @auth realisiert werden können. Wenn ihr noch andere coole Ideen habt, dann lasst es mich gerne wissen.&lt;/p&gt;
&lt;p&gt;Ich liebe es, an Open-Source-Projekten zu arbeiten. Viele Dinge kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt;. Wenn du meine Arbeit dort und meine Blog-Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen:&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;Oder&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;Und schau doch mal auf meiner Seite vorbei&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[Mit ninox.com zum Prototypen deines SaaS Produkt]]></title><description><![CDATA[Hi, Es macht mir viel Spaß unser SaaS Produkt zu entwickeln. In der Minimalempires Community habe ich einen tollen CoFounder mit einer…]]></description><link>https://martinmueller.dev/ninox-mvp/</link><guid isPermaLink="false">https://martinmueller.dev/ninox-mvp/</guid><category><![CDATA[de]]></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;Es macht mir viel Spaß unser SaaS Produkt zu entwickeln. In der &lt;a href=&quot;https://community.minimalempires.de/&quot;&gt;Minimalempires Community&lt;/a&gt; habe ich einen tollen CoFounder mit einer tollen Idee gefunden. Mit der Low-Code Plattform &lt;a href=&quot;https://ninox.com&quot;&gt;ninox.com&lt;/a&gt; wollen wir diese Idee validieren und bauen ein Prototypen. Bisher hatte ich noch keine Erfahrungen mit Low-Code und konnte mir auch nicht vorstellen, dass solche nützlich für mich sind, da ich bereits viel Erfahrung mit Frontend und Backend besitze. Ich wurde ganz klar eines besseren belehrt! In den nächsten Absätzen will ich erklären was ninox.com ist und wie es uns hilft einen Prototypen zu entwickeln.&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; ist eine Cloud-basierte low-code Plattform zum Bauen von Softwarelösungen für kleine und mittelgrosse Unternehmen. Ninox wurde 2013 von &lt;a href=&quot;https://www.linkedin.com/in/frank-boehmer/&quot;&gt;Frank Böhmer&lt;/a&gt; in Deutschland gegründet. Stand 2021 zählte Ninox mehr als 6.000 Kunden. Erwähnenswert ist auch der &lt;a href=&quot;https://www.youtube.com/@ninox1273&quot;&gt;YouTube-Kanal von Ninox&lt;/a&gt; mit viel Content über Ninox. Sowie auch die wöchentlich stattfinden Open Office Hours in englischer und deutscher Variante. Bei diesen können Kunden ihre Fragen und Probleme über ninox einem ninox Mitarbeiter*innen stellen.&lt;/p&gt;
&lt;h2 id=&quot;meine-erfahrung-mit-ninoxcom&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#meine-erfahrung-mit-ninoxcom&quot; aria-label=&quot;meine erfahrung mit 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;Meine Erfahrung mit ninox.com&lt;/h2&gt;
&lt;p&gt;Die Entwicklung eines Prototypen geht mit ninox.com super schnell. Die Definition der Tabelle, also welche Spalten und Spaltentypen die jeweilige Tabelle inne hat, dient quasi auch zur Erstellung der UI. Somit kann super schnell ein Datenmodell und eine darauf aufbauende UI entwickelt werden. Ninox.com hat sich echt coole in pfiffige Ideen überlegt wie eine Datenbanken sinnvoll und nativ mit einer konfigurierbaren UI verbunden werden kann.&lt;/p&gt;
&lt;p&gt;Auch die bereits vorhandene Userverwaltung funktioniert sehr gut. Damit lassen sich einfache Rollen und Permission Schemata gut abbilden.&lt;/p&gt;
&lt;p&gt;Die Community von ninox.com ist sehr aktiv und super hilfsbereit. Diese hat mir immer weitergeholfen wenn ich Probleme bei der Implementierung hatte. Probleme bei der Implementierung hatte ich hauptsächlich nur wenn ich die ninox.com native Programmiersprache verwenden musste. Das war zum Beispiel der Fall wenn die Datenbank queries brauchte und auf diesem bestimmte Berechnungen machen musste.&lt;/p&gt;
&lt;h2 id=&quot;mit-ninoxcom-zum-vollständigen-produkt&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#mit-ninoxcom-zum-vollst%C3%A4ndigen-produkt&quot; aria-label=&quot;mit ninoxcom zum vollständigen produkt permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Mit ninox.com zum vollständigen Produkt?&lt;/h2&gt;
&lt;p&gt;Nein! Wir stossen wir jetzt schon auf Limitationen die mit herkömmlichen Tech-Stacks wie &lt;a href=&quot;https://www.mongodb.com/mern-stack&quot;&gt;MERN&lt;/a&gt; leichter behebbar wären. Auch das fehlen einer Git-Integration was die Entwicklung schwerer macht, da wichtige Tools wie Versionierung und Pull Requests fehlen.&lt;/p&gt;
&lt;h2 id=&quot;fazit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fazit&quot; aria-label=&quot;fazit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fazit&lt;/h2&gt;
&lt;p&gt;Ninox is super für die schnelle Entwicklung eines Prototypen. Darüber hinaus eignet es sich wahrscheinlich nicht für die Entwicklung eines SaaS Produkts. Das war und ist auch nicht der Use-Case von ninox.com weshalb das auch total ok ist. Trotzdem bin ich super beeindruckt wie gut es sich für unseren Prototypen geeignet hat und bin mehr als bereit ninox.com wiederzuverwenden!&lt;/p&gt;
&lt;p&gt;Vielen Dank auch an meinen CoFounder. Es macht mir super viel Spass mit dir zusammen an unserem Produkt, Vision und Zukunft zu arbeiten. Du bist super motiviert und engagiert. Ich freue mich schon wahnsinnig auf unsere weitere Zusammenarbeiten 2023 :)!&lt;/p&gt;
&lt;p&gt;Ich liebe es, an Open-Source-Projekten zu arbeiten. Viele Dinge kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt;. Wenn du meine Arbeit dort und meine Blog-Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen:&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;Oder&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;Und schau doch mal auf meiner Seite vorbei&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 mit cdktf]]></title><description><![CDATA[Hi, In diesem Blog-Post möchte ich kurz erklären, was cdktf ist und wie man damit eine TypeScript-Lambda erstellen kann. Die Motivation…]]></description><link>https://martinmueller.dev/cdktf-lambda/</link><guid isPermaLink="false">https://martinmueller.dev/cdktf-lambda/</guid><category><![CDATA[de]]></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 diesem Blog-Post möchte ich kurz erklären, was cdktf ist und wie man damit eine TypeScript-Lambda erstellen kann. Die Motivation dafür kam durch einen &lt;a href=&quot;https://stackoverflow.com/questions/74740782/how-to-deploy-lambda-using-terraform-created-by-cdktf&quot;&gt;StackOverflow-Beitrag&lt;/a&gt;. Zunächst erkläre ich kurz, was cdktf überhaupt ist und wie man es initialisiert. Anschließend zeige ich die Lösung für die TypeScript-Lambda.&lt;/p&gt;
&lt;h2 id=&quot;was-ist-cdktf&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-ist-cdktf&quot; aria-label=&quot;was ist 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;Was ist cdktf?&lt;/h2&gt;
&lt;p&gt;Das Cloud Development Kit for Terraform (cdktf) ist ein Toolkit zum Erstellen und Verwalten von Cloud-Infrastruktur wie AWS oder Azure mit Terraform. Es ermöglicht es dir, die Infrastruktur mithilfe einer Programmiersprache wie TypeScript oder Python zu definieren.&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;Den gesamten Code findest du in meinem Repository &lt;a href=&quot;https://github.com/mmuller88/cdktf-lambda&quot;&gt;hier&lt;/a&gt;. Ich beschreibe aber noch kurz, wie das Repository erstellt wurde. Initialisiere dein cdktf-Repo mit:&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;Optional kannst du noch Prettier und Linter hinzufügen. In den meisten meiner Projekte verwende ich diese, da sie mir ein schnelles Entwickeln ermöglichen, ohne dass ich mir Gedanken um die Formatierung machen muss.&lt;/p&gt;
&lt;p&gt;Ich verwende das &lt;a href=&quot;https://github.com/terraform-aws-modules/terraform-aws-lambda&quot;&gt;Community Terraform Lambda Modul&lt;/a&gt;, um die Lambda zu definieren. Es erlaubt mir, in nur wenigen Zeilen eine Lambda zu definieren, die mit einer Rolle konfiguriert wird und auch einfach um Policies erweitert werden kann. Das Coole ist, dass cdktf eine Type-Importierung unterstützt. Dafür muss einfach in der cdktf.json-Datei folgendes Modul hinzugefügt werden:&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;Anschließend wird der Befehl cdktf get ausgeführt:&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;Nun kann das Modul im cdktf-Code verwendet werden:&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;Falls die Lambda eigene Dependencies hat, müssen diese noch installiert werden mit:&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;Deploye den cdktf-Stack mit:&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;Die Lambda kann dann zum Beispiel in die main.ts integriert werden:&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;&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;Ich benutze also das Custom Construct NodejsFunction, um den Code von TypeScript in JavaScript zu bundlen und der Lambda zu zeigen, wo sie den gebundelten JavaScript-Code finden kann. Das NodejsFunction Construct sieht so aus:&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;Wie zu sehen ist, bundelt esbuild den TypeScript Code zu JavaScript Code jedesmal wenn &lt;code&gt;cdktf deploy&lt;/code&gt; ausgeführt wird.&lt;/p&gt;
&lt;h2 id=&quot;fazit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fazit&quot; aria-label=&quot;fazit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fazit&lt;/h2&gt;
&lt;p&gt;TypeScript-Lambdas mit cdktf zu bauen bedarf etwas mehr Aufwand im Vergleich zu aws cdk TypeScript-Lambdas. Trotzdem hält sich dieser Aufwand in Grenzen und ich habe dir hier gezeigt, wie du es machen kannst. Falls du den Beitrag hilfreich fandest, lass es mich bitte wissen!&lt;/p&gt;
&lt;p&gt;Ich liebe es, an Open-Source-Projekten zu arbeiten. Viele Dinge kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt;. Wenn du meine Arbeit dort und meine Blog-Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen:&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;Oder&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;Und schau doch mal auf meiner Seite vorbei&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 mit CircleCI]]></title><description><![CDATA[Hi, Terraform CI/CD Staging Pipelines, wobei das CD für Continuous Deployment steht, erlauben ein sicheres und kontinuierliches Entwickeln…]]></description><link>https://martinmueller.dev/tf-pipeline/</link><guid isPermaLink="false">https://martinmueller.dev/tf-pipeline/</guid><category><![CDATA[de]]></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, wobei das CD für Continuous Deployment steht, erlauben ein sicheres und kontinuierliches Entwickeln von Infrastruktur mit Terraform. Üblicherweise wird durch ein Commit im main Branch die Pipeline gestartet und die gewünschten Änderungen zuerst auf der DEV Stage ausgeführt. Durch ein manuelles Approval können dann die Änderungen auf die QA Stage und anschließend auf die PROD Stage mit der Pipeline ausgerollt werden.&lt;/p&gt;
&lt;p&gt;Wie so eine Terraform CI/CD Staging Pipeline mit AWS als Cloud Provider aussehen kann, möchte ich hier gerne vorstellen.&lt;/p&gt;
&lt;h2 id=&quot;warum-eine-cicd-staging-pipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#warum-eine-cicd-staging-pipeline&quot; aria-label=&quot;warum eine 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;Warum eine CI/CD Staging Pipeline?&lt;/h2&gt;
&lt;p&gt;Zusammen mit dem Kunden planen und entwickeln wir ein ein komplexes AWS Setup mit &lt;a href=&quot;https://hasura.io/&quot;&gt;Hasura&lt;/a&gt;, RDS, ECS und vielen weiteren AWS Services. Dieses Setup soll unter anderem auch mit der existierenden Produktionsumgebung in Salesforce interagieren. Es ist also von größter Wichtigkeit neue Funktionalitäten auf einer DEV und QA Umgebung zu testen.&lt;/p&gt;
&lt;p&gt;Diese Umgebungen DEV und QA, sollen sich dabei möglichst ähnlich zur PROD Umgebung verhalten. Darüber hinaus sollen Änderungen schnell auf die PROD Umgebung ausführbar sein mit möglichst wenig benötigten manuellen Schritten. Genau für diese Anforderungen eignet sich eine CI/CD Staging Pipeline.&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;Um eine CI/CD Staging Pipelines zu erstellen ist es best practice für jede stage wie DEV, QA oder PROD einen eigenen AWS Account zu verwenden. Das Pipeline Setup muss also in der Lage sein diese Accounts mit Terraform zu bootstrappen bzw. zu initialisieren und anschließend Änderungen auszurollen.&lt;/p&gt;
&lt;p&gt;Für das Multi-Account Setup habe ich mir den Artikel &lt;a href=&quot;https://cloudly.engineer/2021/terraform-aws-multi-account-setup/aws/&quot;&gt;Terraform AWS Multi-Account Setup&lt;/a&gt; zum Vorbild genommen bei dem mittels Config Files wie &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; und &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; die jeweilige Stage konfiguriert wird. Super cool ist nun, dass damit die gleiche &lt;a href=&quot;https://github.com/mmuller88/tf-pipeline-circleci/blob/main/main.tf&quot;&gt;main.tf&lt;/a&gt; für alle Staging Umgebungen verwendet werden kann.&lt;/p&gt;
&lt;p&gt;Zu oft sehe ich bei Kunden die mit Terraform arbeiten, dass für jede Staging Umgebung eigene TF Files erzeugt werden und Ressourcen hin und her kopiert werden. Das muss aufhören und der hier beschriebene Ansatz kann dabei helfen!&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; ist eine continuous integration and continuous delivery Plattform für DevOps Funktionalitäten. Ähnlich wie auch auf anderen DevOps Plattformen wie Travis oder GitHub Actions wird eine Pipeline yaml Definition im Ordner .circleci mit den Namen config.yml angelegt. Sehr toll finde ich, dass CircleCI manuelle Approvals unterstützt und einfach integrierbar macht mit:&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;Somit können die geplanten Infrastruktur-Änderungen erst begutachtet und dann durchgeführt werden. Den vollständigen Code seht ihr &lt;a href=&quot;https://github.com/mmuller88/tf-pipeline-circleci/blob/main/.circleci/config.yml&quot;&gt;hier&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;ausblick&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ausblick&quot; aria-label=&quot;ausblick permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ausblick&lt;/h2&gt;
&lt;p&gt;Als nächstes möchte ich &lt;a href=&quot;https://github.com/hashicorp/terraform-cdk&quot;&gt;CDKTF&lt;/a&gt; einführen damit die Infrastruktur mit TypeScript definiert werden kann. Ähnlich wie es für mich auch der Fall mit AWS CDK war, verspreche ich mir dadurch ein schnelleres Entwickeln mit Terraform. Der Typen-Support erlaubt mir fehlende Terraform Properties schon früh zu erkennen. Auch ist die Dokumentation von den Properties sehr angenehm und ich muss somit kaum noch in der Terraform Dokumentation nachsehen.&lt;/p&gt;
&lt;p&gt;Danach bin ich auch schon sehr gespannt wie AWS Ressourcen wie Aurora, ECS, VPC und so weiter mit Terraform integriert werden. Das Ganze erweitert mein Set an Tools mit denen ich coole Sachen in AWS bauen kann.&lt;/p&gt;
&lt;h2 id=&quot;fazit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fazit&quot; aria-label=&quot;fazit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fazit&lt;/h2&gt;
&lt;p&gt;Eine CI/CD Staging Pipeline ist ein wichtiges Tool um verlässliche Infrastruktur in AWS zu bauen. Hier in diesem Artikel habe ich euch gezeigt wie ihr es mit Terraform in AWS machen könnt. Da ich noch ein Anfänger in Terraform bin, habe ich eventuell kleine Fehler gemacht. Wenn ihr Verbesserungsvorschläge habt oder einfache coole Projekte mit mir besprechen wollt, schreibt mir gerne an :)!&lt;/p&gt;
&lt;p&gt;Ich liebe es an Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Oder&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;</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 und Amplify runtime-config]]></title><description><![CDATA[Ahoi, Die nahtlose Integration von AWS CDK und Amplify Apps war bisher sehr umständlich! Mit einer runtime-config für die Amplify Frontend…]]></description><link>https://martinmueller.dev/cdk-amplify-runtime-config/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-amplify-runtime-config/</guid><category><![CDATA[de]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><pubDate>Sat, 27 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;Ahoi,&lt;/p&gt;
&lt;p&gt;Die nahtlose Integration von AWS CDK und Amplify Apps war bisher sehr umständlich! Mit einer runtime-config für die Amplify Frontend React App ist es nun wesentlich einfacher. Hier möchte ich dir gerne die Idee der runtime-config vorstellen.&lt;/p&gt;
&lt;p&gt;In meinen Fullstack Projekten nutze ich regelmäßig AWS CDK als Backend. Dabei ist AppSync als GraphQL Implementation die Schnittstelle zwischen dem Frontend und Backend. Das Frontend ist normalerweise eine React SPA (Single Page Application) gehostet in einem S3 Bucket. Zum Verwalten und Authentifizieren der User nutze ich AWS Cognito. Die Frontend React App konfiguriere ich üblicherweise mit AWS Amplify.&lt;/p&gt;
&lt;h2 id=&quot;idee-runtime-config&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#idee-runtime-config&quot; aria-label=&quot;idee 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;Idee runtime-config&lt;/h2&gt;
&lt;p&gt;Die runtime-config erlaubt die Konfiguration von Amplify nach der Build-Phase zur Runtime. Dabei wird dem dist Folder der SPA einem File z.B. runtime-config.json im public Folder mitgegeben welcher zur Runtime der App ausgelesen wird. Diese kann dan zum Beispiel so aussehen:&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;Die runtime-config wird dann dynamisch in der React App geladen via useEffect und 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;Wie du siehst wird ein fetch zum laden der runtime-config.json initial ausgeführt. Danach wird Amplify mit der extrahierten properties konfiguriert.&lt;/p&gt;
&lt;p&gt;Es können auch &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window&quot;&gt;HTML window variablen&lt;/a&gt; zum setzen der Amplify Parameter verwendet werden. Allerdings bevorzuge ich die hier vorgestellt fetch Lösung weil damit potentiell besser auf eine fehlende runtime-config.json oder einzeln fehlende Properties reagiert werden kann. Außerdem sollten window Variablen vermieden werden da diese globalen Zugriff auf den DOM bekommen.&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;Der typische Workflow ohne die runtime-config zum builden und deployen der React App lief bisweilen so ab:&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 mit 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-beispiel&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cdk-beispiel&quot; aria-label=&quot;cdk beispiel permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 Beispiel&lt;/h2&gt;
&lt;p&gt;Der Komplette Code is in meinem &lt;a href=&quot;https://github.com/senjuns/senjuns/blob/main/backend/src/dashboard-stack.ts&quot;&gt;GitHub Senjuns Projekt&lt;/a&gt; einsehbar.&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;Die StaticWebsite ist ein simples L3 CDK Construct mit einem S3 static website bucket als Haupt-Ressource. Mehr Details siehst du &lt;a href=&quot;https://github.com/senjuns/senjuns/blob/main/backend/src/construcs/static-website.ts&quot;&gt;hier&lt;/a&gt;. Die interessanten Details befinden sich aber im &lt;strong&gt;runtimeOptions&lt;/strong&gt; Objekt. Dort werden also die Endpoints für die runtime config für Amplify hinterlegt. Dahinter steckt dann das S3 Bucket Deployment Construct welches die Endpoints via &lt;strong&gt;s3deploy.Source.jsonData(...)&lt;/strong&gt; in die JSON Datei runtime-config.json überführt:&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;Das ist doch mal ne coole CDK integration :) ! Dem BucketDeployment Construct einfach die zwei Parameter wie dem React dist und der runtime-config mitzugeben ist schon eine ziemlich schlaue Idee.&lt;/p&gt;
&lt;h2 id=&quot;workaround-mit-nested-stack-outputs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#workaround-mit-nested-stack-outputs&quot; aria-label=&quot;workaround mit 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 mit nested Stack Outputs&lt;/h2&gt;
&lt;p&gt;Während meiner Arbeit mit der runtime-config bin ich auf ein Problem gestoßen. Es ist nämlich nicht möglich CDK Outputs von einem Nested Stack für die runtime-config zu verwenden. Es gibt aber den Workaround mittels AWS Systems Manager Parameter:&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 oder? Der Nested Stack Output wird einfach in einem SSM String Parameter gespeichert und kann dann später ausgelesen werden. Vielen dank an Adrian Dimech für den tollen &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;fazit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fazit&quot; aria-label=&quot;fazit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fazit&lt;/h2&gt;
&lt;p&gt;AWS CDK und Amplify sind eine starke Kombination. Mit der hier vorgestellten runtime-config fühlt sich diese Kombination wesentlich besser an! Ich habe mir diese Lösung vom &lt;a href=&quot;https://github.com/aws/aws-prototyping-sdk&quot;&gt;aws-prototyping-sdk&lt;/a&gt; abgeschaut. In diesem Repo werden interessante AWS CDK Constructs entwickelt. Ihr solltet es also definitiv mal auschecken!&lt;/p&gt;
&lt;p&gt;Ich hoffe ich konnte auch dir damit einen Anreiz geben mal die runtime-config auszuprobieren. Erzähl mir gerne wie es war.&lt;/p&gt;
&lt;p&gt;Ich liebe es an Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Oder&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/a91982cf204dcf213ceff4c4d3aa000c/title.png</featuredImage><media:content url="https://martinmueller.dev/static/a91982cf204dcf213ceff4c4d3aa000c/title.png" medium="image"/></item><item><title><![CDATA[Catch AWS Lambda Timeouts]]></title><description><![CDATA[Ahoi, AWS Lambda ist wohl einer der berühmtesten wenn nicht der berühmteste compute Service von AWS. Tatsächlich ist Lambda auch mein…]]></description><link>https://martinmueller.dev/cdk-lambda-timeout/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-lambda-timeout/</guid><category><![CDATA[de]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><pubDate>Sun, 10 Jul 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/addedc46ab1d0fb796bcf1853eb39ff6/lambda.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Ahoi,&lt;/p&gt;
&lt;p&gt;AWS Lambda ist wohl einer der berühmtesten wenn nicht der berühmteste compute Service von AWS. Tatsächlich ist Lambda auch mein Lieblingsservice von AWS, da es sehr einfach und unkompliziert das Implementieren der Businesslogik ermöglicht. Schon ein paar mal hatte ich allerdings das Problem, dass das Timeout der Lambda zu gering war und somit der Code nicht komplett ausgeführt wurde. Diesen Fehler zu debuggen oder zu catchen war auch oft anstrengend und nervig. Eine gute Lösung für mich war es die Lambda Duration Metrics zu nutzen um einen Alarm zu definieren.&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;Wie du hier sehen kannst, wird am Anfang eine einfach Lambda JS Function erstellt. Übrigens das &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; Construct unterstützt auch TypeScript. Dann wird der Timeout Alarm definiert der die Duration Metrik und den Timeout Value von der Lambda benutzt zu Konfiguration.&lt;/p&gt;
&lt;p&gt;Danach wird eine Error Topic erstellt über die mittels einer EmailSubscription der ausgelöste Alarm per Email weitergeleitet wird.&lt;/p&gt;
&lt;h2 id=&quot;vorteile&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#vorteile&quot; aria-label=&quot;vorteile permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Vorteile&lt;/h2&gt;
&lt;p&gt;Der Vorteil der Lösung ist, dass der Code der Lambda nicht extra angepasst werden muss und das Problem somit auf Infrastruktur Level bzw. AWS CDK Level gelöst wird. Diese Lösung lässt sich genauso auf andere Lambda Sprachen wie Python oder Java anwenden.&lt;/p&gt;
&lt;h2 id=&quot;fazit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fazit&quot; aria-label=&quot;fazit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fazit&lt;/h2&gt;
&lt;p&gt;Das catchen von Lambda Timeouts ist nervig. Mit ein wenig AWS CDK Code und der Lambda Duration Metrik ist das Problem schnell gelöst.&lt;/p&gt;
&lt;p&gt;Ich liebe es an Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Oder&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/addedc46ab1d0fb796bcf1853eb39ff6/lambda.png</featuredImage><media:content url="https://martinmueller.dev/static/addedc46ab1d0fb796bcf1853eb39ff6/lambda.png" medium="image"/></item><item><title><![CDATA[Mach die AWS prod Umgebung super mit Superwerker]]></title><description><![CDATA[Hi Leute. Ich will mein senjuns project production ready machen. Bisher hatte ich es nur in meinem developer AWS Account deployed. Mein…]]></description><link>https://martinmueller.dev/aws-superwerker/</link><guid isPermaLink="false">https://martinmueller.dev/aws-superwerker/</guid><category><![CDATA[de]]></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 Leute.&lt;/p&gt;
&lt;p&gt;Ich will mein &lt;a href=&quot;https://github.com/senjuns/senjuns&quot;&gt;senjuns project&lt;/a&gt; production ready machen. Bisher hatte ich es nur in meinem developer AWS Account deployed. Mein developer Account hate kine AWS Services konfiguriert die für eine Vernünftige Produktionsumgebung benötigt werden. Das sind zum Beispiel AWS SSO, ControlTower, SecurityHub und noch einige mehr. Da kam das &lt;a href=&quot;https://github.com/superwerker/superwerker&quot;&gt;Superwerker CFN Template&lt;/a&gt; gerade recht. Dieses hat es mir ermöglicht einen neuen AWS Account mit vielen tollen AWS Services fur den Produktionsbetrieb zu konfigurieren. In den folgenden Abschnitten möchte ich gerne darauf eingehen was Superwerker genau ist und wie ich es verwendet habe.&lt;/p&gt;
&lt;h2 id=&quot;was-ist-superwerker&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-ist-superwerker&quot; aria-label=&quot;was ist 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;Was ist Superwerker?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/superwerker/superwerker&quot;&gt;Superwerker&lt;/a&gt; ist eine Open Source AWS CloudFormation Lösung welches die Einrichtung eines AWS Accounts erleichtert. Dabei folgt es best practices für Security und Effizienz. Entwickelt und Maintained wurde/wird das Projekt von AWS Advanced Partnern &lt;a href=&quot;https://github.com/superwerker/superwerker&quot;&gt;kreuzwerker&lt;/a&gt; und &lt;a href=&quot;https://superluminar.io/&quot;&gt;superluminar&lt;/a&gt;. Es hat sogar seine eigene &lt;a href=&quot;superwerker.cloud&quot;&gt;Landingpage&lt;/a&gt;[&lt;a href=&quot;https://superwerker.cloud/&quot;&gt;https://superwerker.cloud/&lt;/a&gt;] mit tollen Inhalten wie einem kurzen Video und mehr. Kaum zu glauben, dass dies ein kostenloses Produkt ist.&lt;/p&gt;
&lt;p&gt;Das Superwerker Deployment hat eine Menge von coolen Features die alle sehr gut in den Docs &lt;a href=&quot;https://github.com/superwerker/superwerker/tree/main/docs/adrs&quot;&gt;hier&lt;/a&gt; erklärt sind. Sehr gut finde ich, dass es zum Beschreiben der einzelnen Features &lt;a href=&quot;https://adr.github.io/&quot;&gt;Architectural Decision Records&lt;/a&gt; verwendet. Nachfolgend erkläre ich die Features mit eigenen Worten.&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; aktiviert den AWS Backup Service und per default wird jeden Tag ein Backup erzeugt. Dabei werden Backups erzeugt von Datenbanken die auch von AWS Backup unterstützt werden.&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; hilft die Kosten in AWS zu überschauen und gibt rechtzeitig eine Warnung falls mehr Kosten als üblich anfallen. Das macht es dadurch, dass der Mittelwert der letzten drei Monate berechnet wird und falls dieser überschritten wird, kommt eine Warnung. Eine echt coole Idee finde ich.&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; vereinfacht das Verwalten von mehreren AWS Accounts mit AWS SSO. Für mich ist das der Hauptgrund warum ich Superwerker verwende. Somit kann ich sehr einfach auf meine verschiedenen AWS Accounts wie build, dev und prod zugreifen. Sehr toll finde ich auch, dass ich mit AWS SSO einfach die AWS Account credentials kopieren und für die AWS CLI verwenden kann.&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; ist ein AWS Service zum finden von möglichen Security Gefahren.&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; ist ein ziemlich cooles Feature welches eine Documentation via AWS CloudWatch Dashboard erzeugt. Diese gibt dann Informationen über zum Beispiel wie ein SSO setup mit externen Identity Providern wie Google gemacht werden kann und noch vieles mehr. Extrem cool ist wie sich diese Documentation auch selber updated wenn bereits gewisse Konfigurationen vorgenommen wurden. Deswegen heißt es ja auch 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 erstellt OpsItems in OpsCenter wenn wenn Emails vom der RootMail Feature versendet werden. Mit dem &lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/notifications.md&quot;&gt;Notifications&lt;/a&gt; Feature werden dann Emails an die spezifizierte Adressen versendet. Somit muss der User sich nicht manuell in die AWS Console einloggen und OpsCenter überprüfen. Durch die Email hat man somit auch eine zentralisierte Sammelstelle für mehrere 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; erstellt die uniformierten Email Adressen für die vom Control Tower erstellten Accounts audit und log archive. Dafür wird eine eigene Hosted Zone zum Beispiel aws.mycompany.test mit Route53 angelegt und die benötigten Einstellungen mit AWS SES zum Erhalt der Emails vorgenommen.&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;Das &lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/securityhub.md&quot;&gt;Security Hub&lt;/a&gt; Feature aktiviert AWS Security Hub für alle Accounts. Der User muss sich in den Audit Account einloggen um die aggregierte Security Hub View zu betrachten.&lt;/p&gt;
&lt;p&gt;Im nächsten Abschnitt möchte ich gerne mehr über meine Experience mit Superwerker berichten.&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;Die Anweisungen zum Ausführen von Superwerker findest du &lt;a href=&quot;https://superwerker.awsworkshop.io/&quot;&gt;hier&lt;/a&gt;. Für mich ging die Installation recht reibungslos. Eine Ausnahme stellte aber der &lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/rootmail.md&quot;&gt;RootMail&lt;/a&gt; Nested Stack da. Ich hatte zuvor meine Domaine senjuns.com und die dazugehörige Hosted Zone aus einem anderen AWS Account importiert. Allerdings habe ich die Name Server von der Domaine nicht ordnungsgemäß in der dafür vorgesehenen Hosted Zone konfiguriert. Durch debuggen der Superwerker Lambdas ist mir dieser Fehler aufgefallen.&lt;/p&gt;
&lt;p&gt;Falls du also auch die folgenden Error logs in der RootMailReady Lambda bekommst, musst du einfach mal überprüfen ob du deine Domaine und die Hosted Zone richtig konfiguriert hast.&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;Falls jemand auf ein gleiches oder ähnliches Problem stoßen sollte, habe ich ein Pull Request mit Troubleshooting Informationen erstellt.&lt;/p&gt;
&lt;h2 id=&quot;fazit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fazit&quot; aria-label=&quot;fazit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fazit&lt;/h2&gt;
&lt;p&gt;Superwerker is ein tolles CloudFormation QuickStart um eine AWS Produktionsumgebung professionell und einfach aufzusetzen. Viele Verbesserungen und neue Features sind bereits im &lt;a href=&quot;https://github.com/superwerker/superwerker/issues&quot;&gt;Superwerker Backlog&lt;/a&gt; geplant. Die Superwerker Community sucht noch nach tatkräftiger Unterstützung beim Implementieren von neuen Feature und Verbesserungen. Ich bin schon sehr gespannt das Superwerker Deployment weiterhin in meinem aktuellen Projekt und in meinen zukünftigen Projekten zu verwenden. Vielen Dank dass du dir meinen Artikel durchgelesen hast. Falls du noch Fragen hast, kannst du mir gerne schreiben.&lt;/p&gt;
&lt;p&gt;Ich liebe es an Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Oder&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[Was ist Serverless?]]></title><description><![CDATA[Um gleich ein mögliches Missverständnis aufzuklären! Serverless heißt nicht dass es keine Server mehr gibt! Im Gegenteil! Cloud Provider wie…]]></description><link>https://martinmueller.dev/serverless/</link><guid isPermaLink="false">https://martinmueller.dev/serverless/</guid><category><![CDATA[de]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><pubDate>Tue, 24 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Um gleich ein mögliches Missverständnis aufzuklären! Serverless heißt nicht dass es keine Server mehr gibt! Im Gegenteil! Cloud Provider wie zum Beispiel AWS, die Serverless anbieten, verfügen über sehr viele Server weltweit. Im nachfolgenden Bild könnt ihr die aktuell verfügbaren AWS Regionen sehen. Das bedeutet an all diesen Plätzen auf der Welt hat AWS mindestens zwei Rechenzentren.&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;So ein Rechenzentrum selbst ist ein riesiges Gebäude mit viel Servertechnik.&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;Jetzt und im Folgenden möchte ich für die jeweilige Sektion anhand von S3 und Lambda als Beispiel erklären.&lt;/p&gt;
&lt;p&gt;S3 ist ein AWS Service der als object storage genutzt werden kann.&lt;/p&gt;
&lt;p&gt;Lambda ist ebenfalls ein AWS Service der aber zum compute also zum berechnen verwendet werden kann. Das wird in der Regel dafür benutzt um die Businesslogik von der Cloud Applikation zu implementieren.&lt;/p&gt;
&lt;h2 id=&quot;warum-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#warum-serverless&quot; aria-label=&quot;warum 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;Warum Serverless?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Geringere Komplexität&lt;/strong&gt;. Als Cloud Entwickler muss ich mich nicht mehr um die Verwaltung (Hardware und Software) der Server. Somit kann ich mich direkter auf die Businesslogik meiner Applikation in der Cloud konzentrieren.
Mit S3 kann ich als Entwickler einfach und unkompliziert über die S3 API Daten speichern. Bei Lambda kann ich die Businesslogik direkt als Code z.B. TypeScript oder Python definieren und an die Lambda API übergeben. Der AWS Lambda Service übernimmt dann den Rest. Ich brauche mich nicht um irgendwelche Betriebssystem-relevante Sachen wie zum Beispiel bei Ec2 zu kümmern.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bessere Skalierbarkeit&lt;/strong&gt;. Serverless Angebote skalieren automatisch per default. So können in S3 beliebig viele Objekte gespeichert werden ohne, dass es der Entwickler das Volumen anpassen muss wie zum Beispiel bei &lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonEBS.html&quot;&gt;AWS EBS&lt;/a&gt;. Auch Lambda kann fast beliebig skalieren. Steigt die Nachfrage zur Ausführung der Businesslogik werden sogar mehrere Lambda Instanzen gestartet um die zeitnahe Abarbeitung zu gewährleisten. Falls keine Ausführung der jeweiligen Businesslogik benötigt wird, werden auch keine Lambda Instanzen gestartet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kostenoptimierung&lt;/strong&gt;. Schon durch den vorherigen Punkt über die bessere Skalierbarkeit lässt sich vermuten dass dadurch Kostenersparnisse zu möglichen Alternativen ergeben können. Dies muss aber nicht immer unbedingt der Fall sein und auch generell Kosten von Serverless mit Alternativen zu vergleichen ist schwierig. Deswegen behandel ich Kostenoptimierungen in diesem Artikel nicht weiter. Nur soviel sei gesagt, dass ich persönlich gerne auf die Serverless Angebote von AWS zugreife da dieses vor allem in der Anfangsphase zu sehr geringe Kosten führt.&lt;/p&gt;
&lt;h2 id=&quot;aber-wie-funktioniert-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aber-wie-funktioniert-serverless&quot; aria-label=&quot;aber wie funktioniert 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;Aber wie funktioniert Serverless?&lt;/h2&gt;
&lt;p&gt;Falls dich die Gründe warum Serverless überzeugt haben, stellst du dir jetzt vielleicht die Frage wie es funktioniert?&lt;/p&gt;
&lt;p&gt;Wie alle AWS Service Angebote funktioniert die Kommunikation mit Serverless Services wie S3 und Lambda per HTTP/S API. Das bedeutet per HTTP Requests können Erstellung- und Änderungsanfragen gestellt werden. Die S3 API findest du in der Documentation &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html&quot;&gt;hier&lt;/a&gt; und für die Lambda API &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/API_Reference.html&quot;&gt;hier&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nun muss sicher der Entwickler aber nicht mit HTTP Requests rumplagen und kann alternativ auch quasi API Wrapper benutzen wie der AWS CLI oder AWS SDK in verschiedenen Programmiersprachen wie TypeScript oder Python. Eine noch bessere und von mir bevorzugte Alternative ist AWS CDK welches m&lt;/p&gt;
&lt;h2 id=&quot;was-gefällt-mir-an-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-gef%C3%A4llt-mir-an-serverless&quot; aria-label=&quot;was gefällt mir an 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;Was gefällt mir an Serverless?&lt;/h2&gt;
&lt;p&gt;Das tolle an Serverless ist für mich, dass es eine tolle Abstraktion ist und das Entwickeln in der Cloud super einfach macht. Somit bin ich gezielt in der Lage die Wünsche und Anforderungen meiner Kunden an ihre Cloud Projekt umzusetzen.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;In diesem Artikel habe ich euch erklärt was Serverless ist und warum ich es so toll finde. Ich glaube aber fest daran dass Serverless noch nicht das Ende der Cloud-Abstraktionen sind. Kürzlich bin ich der Firma &lt;a href=&quot;https://www.linkedin.com/company/monadahq/about/&quot;&gt;Monada&lt;/a&gt; beigetreten die genau das als Ziel verfolgen. Wir wollen eine noch bessere Abstraktion als Serverless schaffen um das Arbeiten mit der Cloud noch toller zu machen. Habt ihr Feedback zu diesem Artikel dann bitte lasst es mich wissen :)! Let&apos;s build!&lt;/p&gt;
&lt;p&gt;Ich liebe es an Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen:&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;Oder&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[Programmatisch AWS Accounts erstellen und löschen]]></title><description><![CDATA[Hi. In AWS ist es best practice neue Accounts zu erstellen wenn zum Beispiel unterschiedliche Stages wie dev, qa und prod für seine Lösung…]]></description><link>https://martinmueller.dev/sdk-org/</link><guid isPermaLink="false">https://martinmueller.dev/sdk-org/</guid><category><![CDATA[de]]></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 ist es best practice neue Accounts zu erstellen wenn zum Beispiel unterschiedliche Stages wie dev, qa und prod für seine Lösung bereitstellen möchte. Auch ist es üblich sogenannte Sandbox AWS Accounts zu erstellen um diese neuen Mitarbeiter zum Testen von AWS Services bereitzustellen. Es gibt noch viele weitere Gründe warum neue AWS Accounts erstellt werden sollten.&lt;/p&gt;
&lt;p&gt;Nun das Erstellen solcher AWS Accounts kann recht aufwendig sein, wenn es manuell gemacht werden muss. Mit AWS Organizations, dem AWS &lt;a href=&quot;https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Organizations.html&quot;&gt;JavaScript SDK&lt;/a&gt; und ein wenig TypeScript Kenntnissen kann der Prozess zum Großteil automatisiert werden. In diesem Post stelle ich vor wie das funktioniert. Dafür erkläre ich zuerst was AWS Organizations überhaupt ist und dann stelle ich die zwei TypeScript Scripte die mittels AWS SDK die AWS Sandbox accounts Erstellen und Löschen können.&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 hilft dabei die AWS Accounts zu verwalten. In sogenannten Organizational Unites (OU) können Accounts zu Gruppen zusammengefasst werden. Darüber hinaus können Security Mechanismen wie Policies Account übergreifend definiert werden. AWS Organizations bietet noch viel viel mehr Funktionalität und ich möchte an dieser Stelle auf die öffentlich Dokumentation hinweisen. Interessant für diesen Beitrag ist, dass es für die AWS Organizations API auch ein &lt;a href=&quot;https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Organizations.html&quot;&gt;JavaScript SDK&lt;/a&gt; wrapper gibt den wir in den nächsten Abschnitten benutzen werden um dynamisch Accounts zu erstellen und zu löschen.&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;Ich habe eine kleine Helfer-Bibliothek in &lt;a href=&quot;https://github.com/mmuller88/aws-accounts&quot;&gt;GitHub&lt;/a&gt; erstellt um das programmatische Erstellen und Löschen von AWS Accounts zu vereinfachen. Ein AWS SDK Script ließe sich dann so ganz leicht bauen wie zum Beispiel:&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; &lt;span class=&quot;token string&quot;&gt;&quot;aws-accounts&quot;&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;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;Der Code ist auch im Repo &lt;a href=&quot;https://github.com/mmuller88/aws-accounts/blob/main/test/createAccountScript.ts&quot;&gt;hier&lt;/a&gt; zu sehen.&lt;/p&gt;
&lt;p&gt;Die Bibliothek is ein leichter Wrapper um AWS SDK TypeScript v.2 . Mit &lt;code&gt;await createAccount(accountName)&lt;/code&gt; wird zuerst der Account erstellt. Anschließend mit &lt;code&gt;await getAccountIdFromName(accountName)&lt;/code&gt; und &lt;code&gt;await moveAccountToOU(accountId)&lt;/code&gt; wird der Account in die definierte OU (Organizational Unit) verschoben.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;In diesem Blog Post habe ich erklärt warum es manchmal erforderlich ist neue AWS Accounts zu erstellen und wie dies gemacht werden kann mit AWS Organizations und dem JavaScript SDK. Dafür habe ich ein createAccount und ein deleteAccount Script erstellt und hier vorgestellt. Fandet ihr den Beitrag hilfreich oder habt ihr Verbesserungsvorschläge? Lasses es mich wissen und schreibt mir :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen:&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;Oder&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[AWS Builder Erfahrung bis jetzt]]></title><description><![CDATA[Hi. Seit März 2022 bin ich ein AWS Community Builder. In diesem Post will ich dir erklären was ein AWS Community Builder ist und wie du…]]></description><link>https://martinmueller.dev/aws-builder/</link><guid isPermaLink="false">https://martinmueller.dev/aws-builder/</guid><category><![CDATA[de]]></category><category><![CDATA[2022]]></category><category><![CDATA[builder]]></category><pubDate>Fri, 29 Apr 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/c7722a9397a9804c72008ebfe2fea067/title.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;Seit März 2022 bin ich ein &lt;a href=&quot;https://aws.amazon.com/developer/community/community-builders/&quot;&gt;AWS Community Builder&lt;/a&gt;. In diesem Post will ich dir erklären was ein AWS Community Builder ist und wie du einer werden kannst. Darüber hinaus werde ich meine persönliche Motivation, warum ich überhaupt ein AWS Builder werden wollte, preisgeben. Am Schluss erkläre ich was aus meiner Perspektive gut und nicht so gut ist am AWS Community Builder Programm.&lt;/p&gt;
&lt;h2 id=&quot;was-ist-und-wie-wirst-du-ein-aws-community-builder&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-ist-und-wie-wirst-du-ein-aws-community-builder&quot; aria-label=&quot;was ist und wie wirst du ein aws community builder permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Was ist und wie wirst du ein AWS Community Builder?&lt;/h2&gt;
&lt;p&gt;Die genau Beschreibung des AWS Community Builder findet ihr &lt;a href=&quot;https://aws.amazon.com/developer/community/community-builders/&quot;&gt;hier&lt;/a&gt;. Kurz zusammengefasst bietet es die Möglichkeit sein AWS zentriertes Netzwerk weiter auszubauen. Ich habe bereits viele spannende Builder kennengelernt. Darüber hinaus helfen sich die Community Mitglieder gegenseitig.&lt;/p&gt;
&lt;p&gt;Ein AWS Community Builder wirst du indem du dich in einem bestimmten Zeitfenster. Für mich war dieses Zeitfenster im Januar. Das nächste Zeitfenster wird sich voraussichtlich &lt;a href=&quot;https://aws.amazon.com/developer/community/community-builders/&quot;&gt;Mitte 2022&lt;/a&gt; wieder öffnen.&lt;/p&gt;
&lt;h2 id=&quot;warum-wollte-ich-ein-aws-builder-werden&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#warum-wollte-ich-ein-aws-builder-werden&quot; aria-label=&quot;warum wollte ich ein aws builder werden permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Warum wollte ich ein AWS Builder werden?&lt;/h2&gt;
&lt;p&gt;In den letzten Jahren habe ich gelernt wie wertvoll und gut es ist sein professionelles Netzwerk auszubauen. Das ermöglicht tolle Gelegenheiten wie zum Beispiel einen neuen tollen Arbeitgeber*in zu finden oder andere interessante Kooperationen einzugehen. Darüber hinaus habe ich in bestimmten Netzwerken wie Slack und auf Meetups viele tolle (AWS) Engineers kennengelernt die mir schon oft geholfen haben oder denen ich helfen durfte.&lt;/p&gt;
&lt;h2 id=&quot;was-gefällt-mir-soweit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-gef%C3%A4llt-mir-soweit&quot; aria-label=&quot;was gefällt mir soweit permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Was gefällt mir soweit?&lt;/h2&gt;
&lt;p&gt;Am meisten gefällt mir der Austausch mit anderen AWS Buildern. Der Austausch findet hauptsächlich im AWS Community Builders Slack statt. Viele von ihnen sind sehr passionierte und engagierte Menschen. Auch ziemlich cool ist, dass Builder dort ihre Blogposts teilen die ich meistens mit Spannung lese.&lt;/p&gt;
&lt;p&gt;Ein cooler Bonus ist der AWS Community Builder Swag. Es ist quasi eine Überraschungsbox mit Swag. Ich bin schon gespannt was dort drinnen sein wird. Bisher ist die Box noch nicht bei mir angekommen. Sehr wichtig bei der Box und dem Inhalt war mir, dass sie nachhaltig hergestellt und versendet wird. AWS hat versichert, dass das der Fall ist. Also brauche ich hier kein schlechtes Gewissen zu haben :).&lt;/p&gt;
&lt;h2 id=&quot;was-gefällt-mir-nicht&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#was-gef%C3%A4llt-mir-nicht&quot; aria-label=&quot;was gefällt mir nicht permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Was gefällt mir nicht&lt;/h2&gt;
&lt;p&gt;Was ich nicht so toll finde ist, dass nur ein relativ geringer Anteil der Bewerbungen zum AWS Community Builder akzeptiert wurden. Es wäre toll sich mit noch mehr Buildern auszutauschen und auch Engineers, die noch nicht so ein hohe Sichtbarkeit haben wie ich, eine Chance zu geben. Allerdings kann ich auch sehr gut verstehen warum AWS die Builder Community nicht zu schnell wachsen lassen sollte.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;Hier in diesem Post habe ich meine Gedanken und Gefühle zum AWS Community Builder zusammengefasst. Natürlich bin ich erst seit wenigen Wochen ein Mitglied und kann von daher kein 360 Grad Feedback geben. Von daher werde ich in ein paar Monaten erneut reflektieren und dich daran teilhaben lassen.&lt;/p&gt;
&lt;p&gt;Wenn du auch noch nach einer coolen AWS Community suchst kann ich dir wärmsten unsere &lt;a href=&quot;https://join.slack.com/t/cdk-dev/shared_invite/zt-xtpfmrqt-6ormYTA0hLdpMSAtTkM_2A&quot;&gt;AWS CDK Slack Community&lt;/a&gt; ans Herz legen. Auch sehr toll ist unsere &lt;a href=&quot;https://join.slack.com/t/awscommunityde/shared_invite/zt-11ptmeylu-zpdZBIWmlbF9NNI3hY0Upw&quot;&gt;DACH AWS Community&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ich liebe es an Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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/c7722a9397a9804c72008ebfe2fea067/title.png</featuredImage><media:content url="https://martinmueller.dev/static/c7722a9397a9804c72008ebfe2fea067/title.png" medium="image"/></item><item><title><![CDATA[AWS Builder experience so far]]></title><description><![CDATA[Hi. As of March 2022, I am an AWS Community Builder. In this post, I will explain to you what an AWS Community Builder is and how you can…]]></description><link>https://martinmueller.dev/aws-builder-eng/</link><guid isPermaLink="false">https://martinmueller.dev/aws-builder-eng/</guid><category><![CDATA[de]]></category><category><![CDATA[2022]]></category><category><![CDATA[builder]]></category><pubDate>Fri, 29 Apr 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/c7722a9397a9804c72008ebfe2fea067/title.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;As of March 2022, I am an &lt;a href=&quot;https://aws.amazon.com/developer/community/community-builders/&quot;&gt;AWS Community Builder&lt;/a&gt;. In this post, I will explain to you what an AWS Community Builder is and how you can become one. In addition, I will reveal my motivation for why I wanted to become an AWS Builder in the first place. In the end, I will explain what is good and not so good about the AWS Community Builder program from my perspective.&lt;/p&gt;
&lt;h2 id=&quot;what-is-and-how-do-you-become-an-aws-community-builder&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-and-how-do-you-become-an-aws-community-builder&quot; aria-label=&quot;what is and how do you become an aws community builder permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 and how do you become an AWS Community Builder?&lt;/h2&gt;
&lt;p&gt;You can find the description of the AWS Community Builder &lt;a href=&quot;https://aws.amazon.com/developer/community/community-builders/&quot;&gt;here&lt;/a&gt;. In short, it provides the opportunity to expand your AWS-focused network. I have already met many exciting and helpful builders.&lt;/p&gt;
&lt;p&gt;You become an AWS Community Builder by applying during a certain time window. For me, that time window was in January. The next time window is expected to open again &lt;a href=&quot;https://aws.amazon.com/developer/community/community-builders/&quot;&gt;mid-2022&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-did-i-want-to-become-an-aws-builder&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-did-i-want-to-become-an-aws-builder&quot; aria-label=&quot;why did i want to become an aws builder permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 did I want to become an AWS Builder?&lt;/h2&gt;
&lt;p&gt;Over the past few years, I have learned how valuable and good it is to build and extend your professional network. This allows for great opportunities such as finding a new great employer or other interesting collaborations. In addition, I have met many great (AWS) engineers in networks like Slack and at meetups who have helped me or whom I can help.&lt;/p&gt;
&lt;h2 id=&quot;what-do-i-like-so-far&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-do-i-like-so-far&quot; aria-label=&quot;what do i like so far permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 so far?&lt;/h2&gt;
&lt;p&gt;What I like most is the exchange with other AWS builders. The exchange mainly takes place in the AWS Community Builders Slack. Many of them are very passionate and dedicated people. Also pretty cool is that builders share their blog posts there which I usually read with excitement.&lt;/p&gt;
&lt;p&gt;A cool bonus is the AWS Community Builder swag. It&apos;s kind of a surprise box of swag. I can&apos;t wait to see what will be in there. So far the box has not arrived to me yet. Very important to me about the box and the contents was that it was sustainably made and shipped. AWS has assured that this is the case. So I don&apos;t need to have a guilty conscience here :).&lt;/p&gt;
&lt;h2 id=&quot;what-i-dont-like&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-i-dont-like&quot; aria-label=&quot;what i dont like permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 don&apos;t like&lt;/h2&gt;
&lt;p&gt;What I don&apos;t like is that only a relatively small percentage of applications to the AWS Community Builder were accepted. It would be great to exchange with even more builders and also give a chance to Engineers who don&apos;t have as high visibility as me yet. However, I can also very well understand why AWS should not let the Builder Community grow too fast. As that would come very hard to handle like organizing events.&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 post, I have summarized my thoughts and feelings about the AWS Community Builder. Of course, I&apos;ve only been a member for a few months and therefore can&apos;t give 360 degree feedback. From there, I will reflect again in a few months and let you share.&lt;/p&gt;
&lt;p&gt;If you are also looking for a cool AWS community, I highly recommend our &lt;a href=&quot;https://join.slack.com/t/cdk-dev/shared_invite/zt-xtpfmrqt-6ormYTA0hLdpMSAtTkM_2A&quot;&gt;AWS CDK Slack Community&lt;/a&gt;. Also great is our &lt;a href=&quot;https://join.slack.com/t/awscommunityde/shared_invite/zt-11ptmeylu-zpdZBIWmlbF9NNI3hY0Upw&quot;&gt;DACH AWS Community&lt;/a&gt;.&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;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://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Werde ein 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/c7722a9397a9804c72008ebfe2fea067/title.png</featuredImage><media:content url="https://martinmueller.dev/static/c7722a9397a9804c72008ebfe2fea067/title.png" medium="image"/></item><item><title><![CDATA[DynamoDB Items nach S3 exportieren]]></title><description><![CDATA[Hi Das Speichern von Daten wie JSON logs in DynamoDB ist eine super Idee da DynamoDB sehr skalierbar ist. Dazu kommt, dass es sehr einfach…]]></description><link>https://martinmueller.dev/dynamodb-to-s3/</link><guid isPermaLink="false">https://martinmueller.dev/dynamodb-to-s3/</guid><category><![CDATA[de]]></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;Das Speichern von Daten wie JSON logs in DynamoDB ist eine super Idee da DynamoDB sehr skalierbar ist. Dazu kommt, dass es sehr einfach ist Daten in eine DynamoDB Tabelle zu transferieren mit z.B. Lambda und AWS SDK. Auch macht es das Analysieren der Logs leichter da z.B. die AWS Console tolle Filtermöglichkeiten bietet umd nach bestimmten sogenannten Tabellen Items zu suchen.&lt;/p&gt;
&lt;p&gt;Das klingt alles sehr gut aber es gibt einen Harken und zwar die Kosten. Mit steigender Anzahl von Items steigen auch die Kosten. Es wäre also ratsam die DynamoDB Daten nach einer gewissen Zeit z.B. 30 Tagen aus der Tabelle zu löschen und in einem S3 zu importieren. Die Kosten für S3 sind wesentlich geringer und es wäre sogar potentiell möglich diese noch weiter zu reduzieren wenn ihr einen günstigeren S3 Tier wie Glacier verwendet.&lt;/p&gt;
&lt;p&gt;Stellt sich jetzt natürlich die Frage wie ihr das am geschicktesten machen könnt? Für mich sehr gut geklappt hat die Kombination &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; und Lambda welche dann in ein S3 Bucket schreibt. Im folgenden Abschnitt möchte ich meine Lösung gerne genauer beschreiben.&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;Ihr findet den Code natürlich in meinem 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;. Die Architektur die ihr auch im Titelbild sehen könnt, ist recht einfach beschrieben. Es wird per DynamoDB streams eine Lambda getriggert, die die gelöschten Item nach S3 wegschreibt. In meinem Beispiel sind die DynamoDB Items einfach JSON logs mit wenigen properties. In eurem Fall kann das DynamoDB Item komplett anders aussehen. Das Grundkonzept müsste aber trotzdem stimmen!&lt;/p&gt;
&lt;p&gt;By the way, if you&apos;re curious how I created the AWS Component Architecture Diagram, check it out &lt;a href=&quot;https://martinmueller.dev/dynamodb-to-s3-eng&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; ist gesetzt da ich ja nur an den items interessiert bin welche gelöscht worden sind.&lt;/p&gt;
&lt;p&gt;Bei der Table Definition wurde ein TimeToLive Attribut mit &lt;code&gt;timeToLiveAttribute: &apos;ttl&apos;&lt;/code&gt; . Es ist dann natürlich wichtig dass eure Komponente welche die Daten nach DynamoDB schreibt das ttl Attribut auch immer setzt. Das ist ein Timestamp der beschreibt wann das Table Item gelöscht werden soll. In meinem Projekt waren das nach 30 Tagen.&lt;/p&gt;
&lt;p&gt;In der Regel solltet ihr nur eine laufende Lambda benötigen um die Daten nach S3 wegzuschreiben &lt;code&gt;reservedConcurrentExecutions: 1&lt;/code&gt;. Das dient zusätzlich zur Absicherung, dass nicht unerwartet viele Aufrufe von Lambda stattfinden.&lt;/p&gt;
&lt;p&gt;Die &lt;strong&gt;addEventSourceMapping&lt;/strong&gt; ist wohl am spannendsten. Was ziemlich cool ist, dass DynamoDB Streams eine Batching-Feature bereitstellt. Die Lambda kann dann die gelöschten Items als Batch verarbeiten und dadurch kann die Anzahl der Lambda-Aufrufe reduziert werden und somit auch die Kosten. Das default DynamoDB default Batching ist aber nicht ganz ideal für unseren Use Case hier deswegen habe ich mittels AWS Console und den Lambda Aufruf Metriken diese optimiert:&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;Die &lt;strong&gt;batchSize&lt;/strong&gt; mit 10000 und das &lt;strong&gt;maxBatchingWindow&lt;/strong&gt; sind maximal gewählt um eine Lambda wirklich nur alle 5 Minuten aufrufen zu müssen:&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 oder? Somit wurde die Anzahl der Lambda Aufrufe massiv reduziert.&lt;/p&gt;
&lt;p&gt;Übrigens die batch size mit 10000 zu wählen ist in meinem Fall ok da es ja JSON Items sind und wir unter der maximalen Größe von 4 MB pro File bleiben wenn ich diese nach S3 wegschreibe. In eurem Fall könnte diese batch size zu hoch sein. Das müsst ihr am besten mit Testen mal ausprobieren. Ich habe dafür z.B. einfach mal 300 Log Items auf einmal gelöscht und es wurde trotzdem erfolgreich alles mit einem Lambda Aufruf nach S3 weggeschrieben.&lt;/p&gt;
&lt;p&gt;Mit Athena und SQL ähnlichen Queries lassen sich dann die Daten nun im S3 Bucket auch auswerten. Wie genau das funktioniert möchte ich aber hier nicht eingehen. Es gibt tolle Tutorials die erklären wie mittels Athena nach bestimmten Informationen in den S3 Daten wie JSON files gequired werden kann.&lt;/p&gt;
&lt;p&gt;Auch noch möchte ich erwähnen, dass ich in manchen Tutorials auch die Verwendung von Kinesis Firehose gesehen habe. Ich glaube aber nicht, dass ihr das benötigt für eure Lösung. DynamoDB Streams hat schon die Möglichkeit zu Batchen. Vielleicht ist es aber auch ein anderer Grund warum Firehose verwendet wurde. Wenn ihr doch einen nützlichen Anwendungsfall für Firehose seht, sagt mir bitte Bescheid.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;DynamoDB Items nach S3 wegzuschreiben um Kosten zu sparen ist super cool. Hier habe ich euch erklärt wie ihr es machen könnt. Habt ihr Feedback zu diesem Post oder andere Vorschläge über was ich berichten kann? Dann sagt mir Bescheid!&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 Diagramme mit cdk-dia <3]]></title><description><![CDATA[Hi. AWS Komponenten Diagramme sind eine tolle Möglichkeit komplexe AWS Architekturen zu visualisieren. Für viele sind solche wesentlich…]]></description><link>https://martinmueller.dev/cdk-dia/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-dia/</guid><category><![CDATA[de]]></category><category><![CDATA[2022]]></category><category><![CDATA[cdk]]></category><pubDate>Thu, 24 Mar 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/7bd513c5cfc01edc91cb90ba0924cfae/diagram.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;AWS Komponenten Diagramme sind eine tolle Möglichkeit komplexe AWS Architekturen zu visualisieren. Für viele sind solche wesentlich intuitiver verständlich als z.B. CDK code. Ich selber arbeite sehr viel mit AWS Komponenten Diagrammen wenn ich neue AWS System entwickle. Was mich daran aber immer gestört hat ist, dass das Erstellen der Diagramme zeitaufwendig ist und diese regelmäßig angepasst werden müssen wenn sich die Architektur ändert.&lt;/p&gt;
&lt;p&gt;Wenn es euch ähnlich geht probiert doch mal &lt;a href=&quot;https://github.com/pistazie/cdk-dia&quot;&gt;cdk-dia&lt;/a&gt; aus. In meinen letzten beiden CDK Projekten habe ich es verwendet und die Erfahrung war einfach überwältigend.&lt;/p&gt;
&lt;h2 id=&quot;wie-funktionierts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wie-funktionierts&quot; aria-label=&quot;wie funktionierts permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wie funktionierts?&lt;/h2&gt;
&lt;p&gt;Das Tool cdk-dia erlaubt es mir AWS Komponenten Diagramme automatisch aus meinem CDK code zu erzeugen. Es folgt sogar dabei den CDK Construct Level 1 und 2 Abstraktionen. Das bedeutet, dass z.B. die großen Komponenten Symbole Level 2 Constructs sind und nur die Hauptkomponente, die üblicherweise &lt;strong&gt;Resource&lt;/strong&gt; als ID bekommt. Somit werden nur die wirklich wichtigen AWS Komponenten gerendert. Das wird auch als collapsing bezeichnet.&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: 71.50000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAAsTAAALEwEAmpwYAAACLklEQVR42qWTy2sTQRzH+2d59iIWb4IHEQv14AMPeqh6ELRgQUEQtORgqU2UYqwefUKLabR5drNJdrPvzHs2u0k2u22SmuSik5LSoJ70y3f4MfObz8ww85uZn/+hGdEGgwEhpNlsRlEUhuG4dYQCEcK/SeRGo9EE3t/ft20bIUQpxRjlC5IslzXdNEyL/CExBwDQ6/UmcLfbFUOMcWFMXW13E2YSIJc01RLlDZGgjNPDrDDnrtim3+8fw2JFRgknEGMCMy8d6TPIrjvSRzHfc4HnQpcBSqAwo+h3GGNKEGBYwNTJbeBsHO2s1Csp22GlCi4pTLc4o2MxghCcgnu9rtdmzRby25RQotVUZTdVlbIIqK9e62cvg/O3WkuroddgvMFdBgmdgqNOd+stTG2Awgcf2EyrVQx5u1bKEGytxo25q9qNRb647No1+OKe8+YBeffQC5s/JrDHo9uz5ccX8Mq1QCk2oLSBMgn47TkzUvG1yqnZ9Olz5aWnjlLQ75wpPbmE1xZ8Hx9MYJeE10+mH80by1eQvFPHxbgjfYK5dSB/cQAvSWY+rwPM5Lw9f2Jz6aIau+m48Oipml50d+7r/bnvsQVxZNeqblvpuJVJmkqRc+o3yNgesTUrGZOTz6T3CSNsT71zvQ40tVJ3TIwc3dAVpaqqqmWZGAJ0aIwAIbDVxr7vsAbsHxxd2HA4FEW3tyfqMgg7QRQGe1EnCscW3WMHQdBqi9huTZXnP3+MXzfR3ECLL2irAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/6502b4ce64b3df48fb964a757de154f8/f1512/decorator_example_collapsed.webp 200w,
/static/6502b4ce64b3df48fb964a757de154f8/f59aa/decorator_example_collapsed.webp 400w,
/static/6502b4ce64b3df48fb964a757de154f8/47a22/decorator_example_collapsed.webp 800w,
/static/6502b4ce64b3df48fb964a757de154f8/5bb53/decorator_example_collapsed.webp 1200w,
/static/6502b4ce64b3df48fb964a757de154f8/485a2/decorator_example_collapsed.webp 1600w,
/static/6502b4ce64b3df48fb964a757de154f8/2edad/decorator_example_collapsed.webp 2550w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/6502b4ce64b3df48fb964a757de154f8/f8f3a/decorator_example_collapsed.png 200w,
/static/6502b4ce64b3df48fb964a757de154f8/6a8a8/decorator_example_collapsed.png 400w,
/static/6502b4ce64b3df48fb964a757de154f8/7842b/decorator_example_collapsed.png 800w,
/static/6502b4ce64b3df48fb964a757de154f8/5ece7/decorator_example_collapsed.png 1200w,
/static/6502b4ce64b3df48fb964a757de154f8/0d4f8/decorator_example_collapsed.png 1600w,
/static/6502b4ce64b3df48fb964a757de154f8/74df5/decorator_example_collapsed.png 2550w&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/6502b4ce64b3df48fb964a757de154f8/7842b/decorator_example_collapsed.png&quot;
            alt=&quot;collapsed&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;(collapsed diagram)&lt;/p&gt;
&lt;p&gt;Möchtet ihr das collapsing verhindern, also auch wirklich alle unterliegenden Komponenten angezeigt bekommen, könnt ihr einen Decorater im Code definieren. Wie genau das funktioniert seht ihr &lt;a href=&quot;https://github.com/pistazie/cdk-dia/tree/main/examples/experimental-decorator-example&quot;&gt;hier&lt;/a&gt; .&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: 69.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAACkklEQVR42qVTW2sTQRjtT+ufEB989EFRoVDRZ0GfFBQELYK1GNoXg9bShlbtTRs3l22Tvc7uJrvZy+wl2bSK702O32xCMdi3DpydYZk5c77vnJkDjdFohPPzc4zH4ytBUM2JRZIk8DwPaZoiz3MMBoMCYp3ngynySyH2ZVkfw+FwQijUCSLO+QzimMN2ugQXrhfAdd0ZdDpuIULs40lEHImodEKYZdmUJJ5CbErR0Wro1srotA5gmBZM0yCYYMxEz9PRcRjCMIbv0RmeFc37j1DclFIL4qSPQNlG2FiDL3+EySwYBoNlMbTbBp4t9SC1e9h+7+DlrQj7pV+XEBKRadmwmEFl+nDMFtqHZRjH+3CYAs8+Rq+rQq63cPOujD3JwcqTJhbmFWy+zmZLjnlEpAmc1h5caY3mXdi2DbWxB9uQcVTVsPpBw9Y3Kl2T0agegNF/aVdH+U0L8kHwjykJKQx8RBGHf/IZQb0E93gLPeUrAqmETF/H0lsN1+9EuP90AFVRoKkKVMIg5zg7C8hlYcqUMB9myPo+kjSGzXSw5g7drsJVDuH8KIHrFSwvy7h2o46Hj62C7OSkBVXTwElE6NNZ6v9IKCRgZ9XH2qMIzS9DuFYD3eYGHLVKBpho1L5D19owDQO1nxLaRGQJt3W1mOMwAA97VOUF4RjPFxQ8mLex8SpFrH1CUH0Hr7UJqyGB376HXqUC0+2SMRpscpmxCSzLKpLBqf8zhOsrKl4sVnG05cFjdbBqGbYmUelNqAuLsLcrMGwGQ21TdHRSOwGjTPIoQkQqE8ruaGLKGL//nOL0NMYwT4roROR2HCf0JOn2QZ9CTsGNwiIJMQ8vkMQR+lmCLBVn84nL4ive9eRtX3mM/gJz7uyqAdnH4AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/a7ddc0014d758986637b4b38bb43634c/f1512/decorator_example_non-collapsed.webp 200w,
/static/a7ddc0014d758986637b4b38bb43634c/f59aa/decorator_example_non-collapsed.webp 400w,
/static/a7ddc0014d758986637b4b38bb43634c/47a22/decorator_example_non-collapsed.webp 800w,
/static/a7ddc0014d758986637b4b38bb43634c/5bb53/decorator_example_non-collapsed.webp 1200w,
/static/a7ddc0014d758986637b4b38bb43634c/485a2/decorator_example_non-collapsed.webp 1600w,
/static/a7ddc0014d758986637b4b38bb43634c/deb1b/decorator_example_non-collapsed.webp 3589w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/a7ddc0014d758986637b4b38bb43634c/f8f3a/decorator_example_non-collapsed.png 200w,
/static/a7ddc0014d758986637b4b38bb43634c/6a8a8/decorator_example_non-collapsed.png 400w,
/static/a7ddc0014d758986637b4b38bb43634c/7842b/decorator_example_non-collapsed.png 800w,
/static/a7ddc0014d758986637b4b38bb43634c/5ece7/decorator_example_non-collapsed.png 1200w,
/static/a7ddc0014d758986637b4b38bb43634c/0d4f8/decorator_example_non-collapsed.png 1600w,
/static/a7ddc0014d758986637b4b38bb43634c/80d3a/decorator_example_non-collapsed.png 3589w&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/a7ddc0014d758986637b4b38bb43634c/7842b/decorator_example_non-collapsed.png&quot;
            alt=&quot;non-collapsed&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;(non-collapsed diagram)&lt;/p&gt;
&lt;p&gt;Das habe ich z.B. bei meinem &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; benutzt:&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;Wenn ihr mehr über mein Prowler Construct wissen wollt schaut &lt;a href=&quot;https://martinmueller.dev/cdk-private-assets&quot;&gt;hier&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;vergleich-mit-aws-console-cloudformation-template&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#vergleich-mit-aws-console-cloudformation-template&quot; aria-label=&quot;vergleich mit 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;Vergleich mit AWS Console Cloudformation template&lt;/h2&gt;
&lt;p&gt;Die AWS Console selbst besitzt auch ein Diagram Tool zum visualisieren von CloudFormation Stacks mit Name AWS CloudFormation Designer. Nähere Informationen findet ihr &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/working-with-templates-cfn-designer.html&quot;&gt;hier&lt;/a&gt;. Ich habe also den Designer mit cdk-dia verglichen und ich finde cdk-dia um einiges besser. cdk-dia schafft es durch das collapsing einen wesentlich besseren Abstraktionsgrad zu erlangen. Außerdem sind die Grafiken von cdk-dia wesentlich hübscher.&lt;/p&gt;
&lt;p&gt;Im nachfolgenden Abschnitt erkläre ich euch wie ihr in eurem CDK Projekt cdk-dia einbauen könnt.&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;Zum kontinuierlichen updaten der cdk-dia Diagramme würde es sich anbieten ein kleines Helferscript in der package.json zu schreiben. Doch vorher solltet ihr erstmal sichergehen dass cdk-dia im dev dependency scope mit &lt;code&gt;yarn add cdk-dia -D&lt;/code&gt; installiert ist.&lt;/p&gt;
&lt;p&gt;Erstellt dann noch einen Ordner mit Namen diagrams und fügt diese Script in die 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;Das Script synthethisiert erst die aktuellen CloudFormation Templates. cdk-dia braucht diese um überhaupt das Diagram erzeugen zu können. Dann wird mit &lt;code&gt;yarn cdk-dia&lt;/code&gt; das Diagram erzeugt und anschließend in den diagrams Ordner verschoben.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;yarn cdk-dia&lt;/code&gt; erzeugt auch immer eine diagram.dot File. Ich empfehle euch die folgenden zwei files in den .gitignore zu packen:&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;Wenn ihr gerne das Diagram in einzelne Bilder aufteilen wollt, könnt ihr auch gezielt nur einzelne CDK Stacks rendern lassen z.B.&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;Auch eine gute Idee ist es den cdk-dia command in den cdk synth Prozess zu integrieren. Das habe ich z.B. bei meinem &lt;a href=&quot;https://github.com/mmuller88/cdk-prowler&quot;&gt;cdk Prowler Construct&lt;/a&gt; mit eingebunden. In der package.json findet ihr das folgende 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;Nun wird bei jedem manuell ausgeführten cdk synth auch immer das cdk-dia diagram gerendert. Cool oder? Wenn ihr mehr über mein Prowler Construct wissen wollt schaut &lt;a href=&quot;https://martinmueller.dev/prowler-cdk&quot;&gt;hier&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;ideen&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ideen&quot; aria-label=&quot;ideen permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ideen&lt;/h2&gt;
&lt;p&gt;Im vorherigen Post habe ich ein kleines Script vorgestellt welches die cdk-dia Diagramme erzeugt. Dieses Script muss leider immer noch manuell ausgeführt werden. Es wäre mega cool wenn sich diese Diagramme quasi selbst updaten. Das sollte möglich sein wenn man Husky pre-commit hooks verwendet. Ich bin das gerade am ausprobieren. Wenn ihr mehr darüber wissen wollt, sagt mir Bescheid.&lt;/p&gt;
&lt;p&gt;Leider konnte cdk-dia meine CDK CD Staging Pipeline nicht vernünftig rendern und ich musste diese per Hand in &lt;a href=&quot;https://draw.io&quot;&gt;https://draw.io&lt;/a&gt; anlegen. Es wäre super cool wenn cdk-dia auch Pipelines abbilden könnte.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;Wenn ihr auch gerne mit AWS Komponenten Diagrammen arbeitet probiert cdk-dia mal aus! Hier in dem Post habe ich beschrieben wie toll das Tool ist und wie einfach es geht. Schreibt mir gerne wenn ihr Fragen habt.&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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/7bd513c5cfc01edc91cb90ba0924cfae/diagram.png</featuredImage><media:content url="https://martinmueller.dev/static/7bd513c5cfc01edc91cb90ba0924cfae/diagram.png" medium="image"/></item><item><title><![CDATA[Private S3 Assets mit Cloudfront, Lambda@Edge und AWS CDK]]></title><description><![CDATA[Moin, Private S3 Assets wie Bilder oder Videos sind ein oft benötigtes Feature für z.B. Apps. Nachdem sich der User eingeloggt hat, sollen…]]></description><link>https://martinmueller.dev/cdk-private-assets/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-private-assets/</guid><category><![CDATA[de]]></category><category><![CDATA[2022]]></category><category><![CDATA[kreuzwerker]]></category><category><![CDATA[s3]]></category><category><![CDATA[cdk]]></category><pubDate>Sun, 13 Feb 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/31eaad727bd581abf3f078392aa8c296/bucket.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Moin,&lt;/p&gt;
&lt;p&gt;Private S3 Assets wie Bilder oder Videos sind ein oft benötigtes Feature für z.B. Apps. Nachdem sich der User eingeloggt hat, sollen Bilder die nur für ihn verfügbar sind, angezeigt werden. Diese befinden sich typischerweise in einem S3 Bucket. Dieser S3 Bucket darf nicht öffentlich verfügbar sein.&lt;/p&gt;
&lt;p&gt;Die bisherige Lösung für so ein Szenario sind &lt;a href=&quot;https://medium.com/@aidan.hallett/securing-aws-s3-uploads-using-presigned-urls-aa821c13ae8d&quot;&gt;presigned URLs&lt;/a&gt;. Bei presigned URLs handelt es sich um speziell generierte URLs die dem Besitzer der URL den Zugriff auf das Asset erlauben. Die presigned URL kann dann z.B. so aussehen:&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;https://presignedurldemo.s3.eu-west-2.amazonaws.com/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;amp;X-Amz-Credential=AKIAJJWZ7B6WCRGMKFGQ%2F20180210%2Feu-west-2%2Fs3%2Faws4_request&amp;amp;X-Amz-Date=20180210T171315Z&amp;amp;X-Amz-Expires=1800&amp;amp;X-Amz-Signature=12b74b0788aa036bc7c3d03b3f20c61f1f91cc9ad8873e3314255dc479a25351&amp;amp;X-Amz-SignedHeaders=host&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mhh wenn ich aber doch schon eine User-Verwaltung z.B. AWS Cognito habe, wäre es dann nicht viel eleganter wenn ich einfach mittels User JWT Token auf solche private Assets zugreifen könnte? Ja absolut! Und um den Programmieraufwand gering zu halten kann dafür Cloudfront und Lambda@Edge benutzt werden.&lt;/p&gt;
&lt;p&gt;In diesem Blogpost möchte ich euch erklären wie mit Cloudfront und Lambda@Edge ein Proxy gebaut werden kann, der es authentisierten Usern erlaubt auf S3 Asset Urls wie z.B. &lt;a href=&quot;https://image.example.com/funny.png&quot;&gt;https://image.example.com/funny.png&lt;/a&gt; zuzugreifen. Wenn der dafür benötigte Token dann auch noch als Cookie gespeichert wird, kann man sogar das HTML img Tag z.B.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;https://image.example.com/funny.png&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;funny.png&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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;verwenden.&lt;/p&gt;
&lt;h2 id=&quot;lösungsansatz&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#l%C3%B6sungsansatz&quot; aria-label=&quot;lösungsansatz permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lösungsansatz&lt;/h2&gt;
&lt;p&gt;Dieses Diagram beschreibt am besten wie der Cloudfront Proxy funktioniert.&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: 432px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 42.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAAHi3RFWHRteGZpbGUAJTNDbXhmaWxlJTIwaG9zdCUzRCUyMmFwcC5kaWFncmFtcy5uZXQlMjIlMjBtb2RpZmllZCUzRCUyMjIwMjItMDItMDhUMDYlM0EyNSUzQTE3LjMxMFolMjIlMjBhZ2VudCUzRCUyMjUuMCUyMChYMTElM0IlMjBMaW51eCUyMHg4Nl82NCklMjBBcHBsZVdlYktpdCUyRjUzNy4zNiUyMChLSFRNTCUyQyUyMGxpa2UlMjBHZWNrbyklMjBDaHJvbWUlMkY5Ny4wLjQ2OTIuOTklMjBTYWZhcmklMkY1MzcuMzYlMjIlMjBldGFnJTNEJTIyTlZhai12bGJyTV9qSWtTemxXWFMlMjIlMjB2ZXJzaW9uJTNEJTIyMTYuNS4zJTIyJTIwdHlwZSUzRCUyMmRldmljZSUyMiUzRSUzQ2RpYWdyYW0lMjBpZCUzRCUyMnBsMHNQVnVUWHFISU80OERvamZLJTIyJTIwbmFtZSUzRCUyMlBhZ2UtMSUyMiUzRTdWcGJjNXM0RlA0MWZxd0hJUWoybzhHWDNVNTJOcnZaZHJkUEhSa0VWaU9RSzRuRTNsOWZDWVFCeTBuanJydHhKazZjTWZyTzBlMWN2aU1nQXhqbG13Vkg2OVZ2TE1GMDREckpaZ0NuQTljRjBQZlVsMGEyTlRKMiUyRlJySU9FbU1VZ3Zja24lMkJ4QVIyRGxpVEJvcWNvR2FPU3JQdGd6SW9DeDdLSEljN1pRMTh0WmJRJTJGNnhwbDJBSnVZMFJ0OUclMkJTeUpWQndkVzRGZnlDU2JZeVU0JTJGY29CYmtxRkUyT3hFcmxMQ0hEZ1JuQXhoeHhtUjlsVzhpVExYeEdydlUlMkZlYVBTSGNMNDdpUXolMkJrUUxGS1NobUFoN3Q0VDlpN2FmRjM5c1h4blJybEh0RFFidm9XcVBSRUNTMkhXTGJlTk1jUWRsckhlbFRPQTRacVJRbGJXOVVQMVVaTkg5WiUyQnZWQ09ORExXdkxmQVFGdGdnc05YVUZ6ZzB3ejU0Q0F0c0VOaHF1dFdzdWc4ZXdnTGZYdkYlMkJiM0NnTjlqcnJUNHdaS1drcE1EUkxvNjFqVk5XeUloUnhpdjdRJTJGVTcxODROTTQ0U2dudXlLMmNDWWRDUlRRbFhBeEZXS0huQnVJN0dNQ1dVZHNjTEFoWEpDaGVTc3p2Y2thVFZqNUlrU0t4d1lwWnpqN2trS2pldTBSTFRHeWFJR1g3SnBHUjVSMkZDU2FZRmtxMFZpa3dyVnF2Q2FvSndKWE9xMnNEczBHUTljSnUyaVRnOUpSTHIyaHdwMmVoMWhDcU4xbHFZYnpMTk9FUDBJTHdoeDRLVlBNYSUyRnhubzlvV3JXVjMwdEFaWE1UcHNtQjlUYThhWURtVFJhWUpaanliZEt4VWo5SzVQU2h0TkFNOFJEeXhDZVVWbDF1S0hCa09Ha2JEZHltN2Jxd21UdUVWbnNXbGtjc2F3Z2tsMHklMkJCVmw4TnozQW05OFhBWkhBWUJnJTJGbVl5T0RaaGZaSTBobTQlMkZqVjNQdGRJWWp1dzBickNUcHpHd3ElMkZGSHpFbXExJTJGeVg4bTVocFROTzFHSEZOSFdBc0l3VmlNNWFOT1NzTEpLZCUyQjF1ZGE2WWRXem53QzVaeWF6eUl5c3E2SGZjJTJCYXVqYVgwOXNCNXJqR3VJWmxrJTJGb21ST2kzc3VUYnVPWUlrbnUlMkJ3ZXowenZCSnRPRldyNDVFNzJFQjdvVWt1QVVsVlQlMkJMMzRCWiUyQlVYYU5jNHlzb2s1Y282bHpKM1RtV3VqZEVEUlc3cyUyQmRPNWUxeVI4eWZRQ2YyM1UlMkJUYXVJWWgxWHNJVVh5WFZUeHlCQTg4dnhCNjNwbWRaNEdkN0UwaHZLbzJ2ZVRxS3ROWEwxWVhUODNLM2pOWjJUMHJWdllzUjEyamZKbWdnZWRvYTElMkJJJTJCWnlJJTJCWHYzSDhGbzVuakhVZlBVOFNNUXZCbHFwblZ3JTJGeFRXZGIwWFp0M0F5dVhmbHhLUjRveEk5OGZwMVglMkJWOURxMlhQSW4lMkZscGkwYmtmMmZmTkpJNnhFRlVZcVNoNndSdEg1U0slMkIlMkZjZjByeHFmZEdQb044M3BwaXVjYnJ1dEcxWHVsUWwxcmxmZ3ozZjg2TlNPcjdwT09FZmJqb0lwZWUzSU54cG9TY0hkZXlZQkRDbTBRVlNQMkliVWJtayUyRkhtVyUyQkZXVWZoTEw4azdYN1B4V2JnaFg0d05Ob3JUNjFhb2xSUHJzeVVya1M4OWs5cmc4eDRMSFNVb3BxcmhPVUROYzVzNUxSdktYcmhNN3JLZ3VqWjdJRFBLdXlNTEtzSHBkQ0I3N3JKQ3clMkZXTEx4QnVWcmlvZXgxcm9jeWwlMkZOb2Z6eXZPUzdoM0pGSHhKJTJGOWslMkYwY20lMkYlMkZyUUJvS08zMGJ3VlVzMzM5WHhmejlwOG80T3diJTNDJTJGZGlhZ3JhbSUzRSUzQyUyRm14ZmlsZSUzRcBOESIAAAG5SURBVHjabZK7jtNQEIb9OjwCFQ9AicQDUJEGid2Giyh224gGGtBKiAItFaLlCSi2Y7lEjuPYXt/t2PElduz48nEcNpGCMkdHozNz/v/8M3MkVVXRdR3DMKjrDT0tvp1yee7xZbygyGrattnGzVnCxYnD57OAdFmQpDFlvubH/IrRp/uMv50iaZrGQDr4OF5S1WtcK+L9iwkfzxWypKQoVqyrAnXiMX58zcUrmShMieIF2TLnavKdB2/ucfb1BKmua8qyZGdd12HaLvJUR1aEctOm7/ttbrUq+HUt8+fnVGDWe0yaZchzRewZUlVVQkGxTQzAYduOh6YbWLaD54d7YJ5nmDcajmPtRQz327ajbTo2m+ZQ4Y7wf9vF1uLxIIyJltm238dMGqTneb5D7n2fJPRp+u84rNvUwvxNHqoH1w8ILVHeVJ0L2S0zRUEVE09tm/DJU8JnL8l8H83QRV99NsGU8PUd4nd36aqMY6yScWOjqBqpUON7Hl4YEpsW6qMRxulzkiDA9VyCaEnpzbHfPsT9MKKry+OEURzj+sFBcJi0ZXvo4rHuFtA0DUM1um6Kb6aLnHW0338B0Miecei+HsIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/ea860604640e013db3fd64df9c499204/f1512/cdkPrivateAssetBucket.webp 200w,
/static/ea860604640e013db3fd64df9c499204/f59aa/cdkPrivateAssetBucket.webp 400w,
/static/ea860604640e013db3fd64df9c499204/09881/cdkPrivateAssetBucket.webp 432w&quot;
              sizes=&quot;(max-width: 432px) 100vw, 432px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/ea860604640e013db3fd64df9c499204/f8f3a/cdkPrivateAssetBucket.png 200w,
/static/ea860604640e013db3fd64df9c499204/6a8a8/cdkPrivateAssetBucket.png 400w,
/static/ea860604640e013db3fd64df9c499204/7c246/cdkPrivateAssetBucket.png 432w&quot;
            sizes=&quot;(max-width: 432px) 100vw, 432px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/ea860604640e013db3fd64df9c499204/7c246/cdkPrivateAssetBucket.png&quot;
            alt=&quot;Diagram&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;Der Flow zum Zugriff auf das Asset is sehr simpel. Zuerst holt sich der User ein gültiges Cognito Token. Das kann z.B. über die Amplify UI, der hosted Cognito login UI oder einer Lambda passieren. Dann wird auf das Asset mittels GET Request zugegriffen z.B. &lt;a href=&quot;https://image.example.com/funny.png&quot;&gt;https://image.example.com/funny.png&lt;/a&gt; . Der Request benötigt ein Cookie mit dem Namen token und dem Cognito Token als Value.&lt;/p&gt;
&lt;p&gt;Zur Erinnerung das ist notwendig wenn man das HTML img tag verwenden möchte. Das img Tag akzeptiert keine Tokens im Header. Alternativ könnte man das Token wohl noch als URL Parameter codieren. Als curl command würde es in etwa so aussehen:&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;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--location&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--request&lt;/span&gt; GET &lt;span class=&quot;token string&quot;&gt;&quot;https://image.example.com/funny.png&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--cookie&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cookie: token=ey...&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Zum Testen der URL empfehle ich aber lieber Postman da es auch Bilder im Response vernünftig anzeigen kann.&lt;/p&gt;
&lt;h2 id=&quot;aws-cdk-custom-construct&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-cdk-custom-construct&quot; aria-label=&quot;aws cdk custom construct permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 Custom Construct&lt;/h2&gt;
&lt;p&gt;Ich habe ein AWS CDK Custom Construct geschrieben um private Assets via Cognito Token einfach zu integrieren. In GitHub auf &lt;a href=&quot;https://github.com/mmuller88/cdk-private-asset-bucket&quot;&gt;https://github.com/mmuller88/cdk-private-asset-bucket&lt;/a&gt; könnt ihr genau sehen wie das Construct funktioniert. Das Construct hat ein recht einfach Interface:&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;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PrivateAssetBucketProps&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; assetBucketName&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;/**
     * if you want to use an imported bucket instead
     */&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; assetBucketNameImport&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 keyword&quot;&gt;readonly&lt;/span&gt; customDomain&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CustomDomain&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; userPoolId&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;readonly&lt;/span&gt; userPoolClientId&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;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CustomDomain&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; zone&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; route53&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;IHostedZone&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/**
     * domainName needs to be part of the hosted zone
     * e.g.: image.example.com
     */&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&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;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mit dem optionalen &lt;strong&gt;assetBucketName&lt;/strong&gt; wird dem erzeugtem Bucket ein Namen vergeben. Lässt man diese Property aus wird der Name vom CDK Naming-Algorithmus bestimmt also eine Zusammensetzung von Stackname, Constructname und zufälligem postfix. Möchte man aber lieber einen existierenden Bucket importieren kann das mit &lt;strong&gt;assetBucketNameImport&lt;/strong&gt; gemacht werden. In diesem Fall wird die vorherige Property ignoriert.&lt;/p&gt;
&lt;p&gt;Das &lt;strong&gt;customDomain&lt;/strong&gt; Object mit den Properties &lt;strong&gt;zone&lt;/strong&gt; und &lt;strong&gt;domainName&lt;/strong&gt; erlaubt die Vergabe eines Custom Domain wie z.B. &lt;a href=&quot;https://mail.example.com&quot;&gt;https://mail.example.com&lt;/a&gt; . Wichtig hierbei ist, dass die Zone sich in Kontrolle des ausführenden AWS Accounts befindet und das auch der domainName ein Teil der Zone ist. Zu guter Letzt werden die User Pool infos mit &lt;strong&gt;userPoolId&lt;/strong&gt; und &lt;strong&gt;userPoolClientId&lt;/strong&gt; angegeben. Dadurch weiß die Lambda@Edge gegen wohin das Token verifiziert werden muss.&lt;/p&gt;
&lt;h2 id=&quot;ausblick&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ausblick&quot; aria-label=&quot;ausblick permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ausblick&lt;/h2&gt;
&lt;p&gt;Es wäre cool wenn auch andere Identity Provider außer Cognito wie eventuell Google oder Okta verwendet werden könnten zur Validierung des Tokens.&lt;/p&gt;
&lt;p&gt;Was auch noch fehlt sind private User Scope. Das wären quasi Unterverzeichnisse im privaten Bucket auf welcher dann nur der validierte User zugreifen kann. Zurzeit können die validierten User nämlich noch auf alle Assets im Bucket zugreifen.&lt;/p&gt;
&lt;p&gt;Auch wäre es super mal zu versuchen inwiefern Cloudfront Function sich eignet anstelle von Lambda@Edge. Cloudfront Functions sind quasi eine abgespeckte Version von Lambda@Edge. Diese haben eine reduzierte Funktionalität und reduzierte Ressourcen. Sind dafür aber günstiger pro Aufruf. Ich bin sehr zuversichtlich, dass Cloudfront Functions ausreichen zum validieren der Tokens.&lt;/p&gt;
&lt;p&gt;Falls ihr eines der hier angesprochenen Features bereits benötigt oder andere coole Feature Ideen habt schreibt mir gerne oder erzeugt direkt Issues im Construct Repo &lt;a href=&quot;https://github.com/mmuller88/cdk-private-asset-bucket&quot;&gt;https://github.com/mmuller88/cdk-private-asset-bucket&lt;/a&gt; . Gerne könnte ihr auch PRs schreiben um euer Feature eingebaut zu bekommen.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;Private S3 Assets wie Bilder oder Videos werden fast immer in modernen Apps benötigt. Bisher konnten solche nur per umständlichen presigned URLs private gehalten werden. Diese Lösung scheint aber nicht optimal da sie keine User Tokens verwendet um auf die Assets zuzugreifen. Hier in diesem Blogpost habe ich euch eine Variante vorgestellt bei der man mit Cognito User Tokens seine privaten S3 Assets Verfügbar machen kann. Wenn euch der Beitrag gefällt oder ihr Fragen und Anregungen habt, schreibt mir doch gerne.&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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/31eaad727bd581abf3f078392aa8c296/bucket.jpg</featuredImage><media:content url="https://martinmueller.dev/static/31eaad727bd581abf3f078392aa8c296/bucket.jpg" medium="image"/></item><item><title><![CDATA[Private S3 Assets with Cloudfront, Lambda@Edge and AWS CDK]]></title><description><![CDATA[Hi, Private S3 assets like images or videos are a frequently needed feature for apps. After the user has logged in, those private assets are…]]></description><link>https://martinmueller.dev/cdk-private-assets-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-private-assets-eng/</guid><category><![CDATA[de]]></category><category><![CDATA[2022]]></category><category><![CDATA[kreuzwerker]]></category><category><![CDATA[s3]]></category><category><![CDATA[cdk]]></category><pubDate>Sun, 13 Feb 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/31eaad727bd581abf3f078392aa8c296/bucket.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;Private S3 assets like images or videos are a frequently needed feature for apps. After the user has logged in, those private assets are shown to him. These are typically stored in an S3 bucket. This S3 bucket must not be publicly available.&lt;/p&gt;
&lt;p&gt;The common solution for such a scenario are &lt;a href=&quot;https://medium.com/@aidan.hallett/securing-aws-s3-uploads-using-presigned-urls-aa821c13ae8d&quot;&gt;presigned URLs&lt;/a&gt;. Presigned URLs are specially generated URLs that allow the owner of that URL to access the asset. A presigned URL could look like this:&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;https://presignedurldemo.s3.eu-west-2.amazonaws.com/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;amp;X-Amz-Credential=AKIAJJWZ7B6WCRGMKFGQ%2F20180210%2Feu-west-2%2Fs3%2Faws4_request&amp;amp;X-Amz-Date=20180210T171315Z&amp;amp;X-Amz-Expires=1800&amp;amp;X-Amz-Signature=12b74b0788aa036bc7c3d03b3f20c61f1f91cc9ad8873e3314255dc479a25351&amp;amp;X-Amz-SignedHeaders=host&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mhh but if I already have a user management system like AWS Cognito, wouldn&apos;t it be more elegant if I could simply access private assets using the user JWT tokens? Yes absolutely! And to keep the programming effort low Cloudfront and Lambda@Edge can be used.&lt;/p&gt;
&lt;p&gt;In this blogpost I want to explain how Cloudfront and Lambda@Edge can be used to build a proxy that allows authenticated users to access S3 asset urls such as &lt;a href=&quot;https://image.example.com/funny.png&quot;&gt;https://image.example.com/funny.png&lt;/a&gt; . If the token needed for this is then also stored as a cookie, you can even use the HTML img tag like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;https://image.example.com/funny.png&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;funny.png&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 punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;solution-approach&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#solution-approach&quot; aria-label=&quot;solution 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;Solution Approach&lt;/h2&gt;
&lt;p&gt;This diagram best describes how the Cloudfront Proxy works.&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: 432px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 42.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAAHi3RFWHRteGZpbGUAJTNDbXhmaWxlJTIwaG9zdCUzRCUyMmFwcC5kaWFncmFtcy5uZXQlMjIlMjBtb2RpZmllZCUzRCUyMjIwMjItMDItMDhUMDYlM0EyNSUzQTE3LjMxMFolMjIlMjBhZ2VudCUzRCUyMjUuMCUyMChYMTElM0IlMjBMaW51eCUyMHg4Nl82NCklMjBBcHBsZVdlYktpdCUyRjUzNy4zNiUyMChLSFRNTCUyQyUyMGxpa2UlMjBHZWNrbyklMjBDaHJvbWUlMkY5Ny4wLjQ2OTIuOTklMjBTYWZhcmklMkY1MzcuMzYlMjIlMjBldGFnJTNEJTIyTlZhai12bGJyTV9qSWtTemxXWFMlMjIlMjB2ZXJzaW9uJTNEJTIyMTYuNS4zJTIyJTIwdHlwZSUzRCUyMmRldmljZSUyMiUzRSUzQ2RpYWdyYW0lMjBpZCUzRCUyMnBsMHNQVnVUWHFISU80OERvamZLJTIyJTIwbmFtZSUzRCUyMlBhZ2UtMSUyMiUzRTdWcGJjNXM0RlA0MWZxd0hJUWoybzhHWDNVNTJOcnZaZHJkUEhSa0VWaU9RSzRuRTNsOWZDWVFCeTBuanJydHhKazZjTWZyTzBlMWN2aU1nQXhqbG13Vkg2OVZ2TE1GMDREckpaZ0NuQTljRjBQZlVsMGEyTlRKMiUyRlJySU9FbU1VZ3Zja24lMkJ4QVIyRGxpVEJvcWNvR2FPU3JQdGd6SW9DeDdLSEljN1pRMTh0WmJRJTJGNnhwbDJBSnVZMFJ0OUclMkJTeUpWQndkVzRGZnlDU2JZeVU0JTJGY29CYmtxRkUyT3hFcmxMQ0hEZ1JuQXhoeHhtUjlsVzhpVExYeEdydlUlMkZlYVBTSGNMNDdpUXolMkJrUUxGS1NobUFoN3Q0VDlpN2FmRjM5c1h4blJybEh0RFFidm9XcVBSRUNTMkhXTGJlTk1jUWRsckhlbFRPQTRacVJRbGJXOVVQMVVaTkg5WiUyQnZWQ09ORExXdkxmQVFGdGdnc05YVUZ6ZzB3ejU0Q0F0c0VOaHF1dFdzdWc4ZXdnTGZYdkYlMkJiM0NnTjlqcnJUNHdaS1drcE1EUkxvNjFqVk5XeUloUnhpdjdRJTJGVTcxODROTTQ0U2dudXlLMmNDWWRDUlRRbFhBeEZXS0huQnVJN0dNQ1dVZHNjTEFoWEpDaGVTc3p2Y2thVFZqNUlrU0t4d1lwWnpqN2trS2pldTBSTFRHeWFJR1g3SnBHUjVSMkZDU2FZRmtxMFZpa3dyVnF2Q2FvSndKWE9xMnNEczBHUTljSnUyaVRnOUpSTHIyaHdwMmVoMWhDcU4xbHFZYnpMTk9FUDBJTHdoeDRLVlBNYSUyRnhubzlvV3JXVjMwdEFaWE1UcHNtQjlUYThhWURtVFJhWUpaanliZEt4VWo5SzVQU2h0TkFNOFJEeXhDZVVWbDF1S0hCa09Ha2JEZHltN2Jxd21UdUVWbnNXbGtjc2F3Z2tsMHklMkJCVmw4TnozQW05OFhBWkhBWUJnJTJGbVl5T0RaaGZaSTBobTQlMkZqVjNQdGRJWWp1dzBickNUcHpHd3ElMkZGSHpFbXExJTJGeVg4bTVocFROTzFHSEZOSFdBc0l3VmlNNWFOT1NzTEpLZCUyQjF1ZGE2WWRXem53QzVaeWF6eUl5c3E2SGZjJTJCYXVqYVgwOXNCNXJqR3VJWmxrJTJGb21ST2kzc3VUYnVPWUlrbnUlMkJ3ZXowenZCSnRPRldyNDVFNzJFQjdvVWt1QVVsVlQlMkJMMzRCWiUyQlVYYU5jNHlzb2s1Y282bHpKM1RtV3VqZEVEUlc3cyUyQmRPNWUxeVI4eWZRQ2YyM1UlMkJUYXVJWWgxWHNJVVh5WFZUeHlCQTg4dnhCNjNwbWRaNEdkN0UwaHZLbzJ2ZVRxS3ROWEwxWVhUODNLM2pOWjJUMHJWdllzUjEyamZKbWdnZWRvYTElMkJJJTJCWnlJJTJCWHYzSDhGbzVuakhVZlBVOFNNUXZCbHFwblZ3JTJGeFRXZGIwWFp0M0F5dVhmbHhLUjRveEk5OGZwMVglMkJWOURxMlhQSW4lMkZscGkwYmtmMmZmTkpJNnhFRlVZcVNoNndSdEg1U0slMkIlMkZjZjByeHFmZEdQb044M3BwaXVjYnJ1dEcxWHVsUWwxcmxmZ3ozZjg2TlNPcjdwT09FZmJqb0lwZWUzSU54cG9TY0hkZXlZQkRDbTBRVlNQMkliVWJtayUyRkhtVyUyQkZXVWZoTEw4azdYN1B4V2JnaFg0d05Ob3JUNjFhb2xSUHJzeVVya1M4OWs5cmc4eDRMSFNVb3BxcmhPVUROYzVzNUxSdktYcmhNN3JLZ3VqWjdJRFBLdXlNTEtzSHBkQ0I3N3JKQ3clMkZXTEx4QnVWcmlvZXgxcm9jeWwlMkZOb2Z6eXZPUzdoM0pGSHhKJTJGOWslMkYwY20lMkYlMkZyUUJvS08zMGJ3VlVzMzM5WHhmejlwOG80T3diJTNDJTJGZGlhZ3JhbSUzRSUzQyUyRm14ZmlsZSUzRcBOESIAAAG5SURBVHjabZK7jtNQEIb9OjwCFQ9AicQDUJEGid2Giyh224gGGtBKiAItFaLlCSi2Y7lEjuPYXt/t2PElduz48nEcNpGCMkdHozNz/v/8M3MkVVXRdR3DMKjrDT0tvp1yee7xZbygyGrattnGzVnCxYnD57OAdFmQpDFlvubH/IrRp/uMv50iaZrGQDr4OF5S1WtcK+L9iwkfzxWypKQoVqyrAnXiMX58zcUrmShMieIF2TLnavKdB2/ucfb1BKmua8qyZGdd12HaLvJUR1aEctOm7/ttbrUq+HUt8+fnVGDWe0yaZchzRewZUlVVQkGxTQzAYduOh6YbWLaD54d7YJ5nmDcajmPtRQz327ajbTo2m+ZQ4Y7wf9vF1uLxIIyJltm238dMGqTneb5D7n2fJPRp+u84rNvUwvxNHqoH1w8ILVHeVJ0L2S0zRUEVE09tm/DJU8JnL8l8H83QRV99NsGU8PUd4nd36aqMY6yScWOjqBqpUON7Hl4YEpsW6qMRxulzkiDA9VyCaEnpzbHfPsT9MKKry+OEURzj+sFBcJi0ZXvo4rHuFtA0DUM1um6Kb6aLnHW0338B0Miecei+HsIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/ea860604640e013db3fd64df9c499204/f1512/cdkPrivateAssetBucket.webp 200w,
/static/ea860604640e013db3fd64df9c499204/f59aa/cdkPrivateAssetBucket.webp 400w,
/static/ea860604640e013db3fd64df9c499204/09881/cdkPrivateAssetBucket.webp 432w&quot;
              sizes=&quot;(max-width: 432px) 100vw, 432px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/ea860604640e013db3fd64df9c499204/f8f3a/cdkPrivateAssetBucket.png 200w,
/static/ea860604640e013db3fd64df9c499204/6a8a8/cdkPrivateAssetBucket.png 400w,
/static/ea860604640e013db3fd64df9c499204/7c246/cdkPrivateAssetBucket.png 432w&quot;
            sizes=&quot;(max-width: 432px) 100vw, 432px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/ea860604640e013db3fd64df9c499204/7c246/cdkPrivateAssetBucket.png&quot;
            alt=&quot;Diagram&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;The flow to access the asset is very simple. First the user gets a valid Cognito token. This can be done via the Amplify UI, the hosted Cognito login UI or a Lambda. Then the asset is accessed via a GET request, for example &lt;a href=&quot;https://image.example.com/funny.png&quot;&gt;https://image.example.com/funny.png&lt;/a&gt; . The request requires a cookie with the name token and the Cognito token as value.&lt;/p&gt;
&lt;p&gt;Remember this is necessary if you want to use the HTML img tag. The img tag does not accept tokens in the header. Alternatively, you could code the token as URL parameter. As a curl command it would 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;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--location&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--request&lt;/span&gt; GET &lt;span class=&quot;token string&quot;&gt;&quot;https://image.example.com/funny.png&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--cookie&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cookie: token=ey...&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For testing the URL, I recommend Postman because it can also display images in the response.&lt;/p&gt;
&lt;h2 id=&quot;aws-cdk-custom-construct&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-cdk-custom-construct&quot; aria-label=&quot;aws cdk custom construct permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 Custom Construct&lt;/h2&gt;
&lt;p&gt;I wrote an AWS CDK Custom Construct to easily integrate private assets via Cognito Token. You can see exactly how the construct works in GitHub at &lt;a href=&quot;https://github.com/mmuller88/cdk-private-asset-bucket&quot;&gt;https://github.com/mmuller88/cdk-private-asset-bucket&lt;/a&gt;. The construct has a pretty simple interface:&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;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PrivateAssetBucketProps&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; assetBucketName&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;/**
     * if you want to use an imported bucket instead
     */&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; assetBucketNameImport&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 keyword&quot;&gt;readonly&lt;/span&gt; customDomain&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CustomDomain&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; userPoolId&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;readonly&lt;/span&gt; userPoolClientId&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;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CustomDomain&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; zone&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; route53&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;IHostedZone&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/**
     * domainName needs to be part of the hosted zone
     * e.g.: image.example.com
     */&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&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;
&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 optional &lt;strong&gt;assetBucketName&lt;/strong&gt; a name is assigned to the created bucket. If you omit this property, the name is determined by the CDK naming algorithm, a composition of stackname, constructname and random postfix. If you prefer to import an existing bucket you can do this with &lt;strong&gt;assetBucketNameImport&lt;/strong&gt;. In this case the previous property is ignored.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;customDomain&lt;/strong&gt; object with the properties &lt;strong&gt;zone&lt;/strong&gt; and &lt;strong&gt;domainName&lt;/strong&gt; allows the assignment of a custom domain like e.g. &lt;a href=&quot;https://mail.example.com&quot;&gt;https://mail.example.com&lt;/a&gt; . It is important that the zone is in control of the running AWS account and that the domainName is also part of the zone. Last but not least the user pool infos are specified with &lt;strong&gt;userPoolId&lt;/strong&gt; and &lt;strong&gt;userPoolClientId&lt;/strong&gt;. This way the Lambda@Edge knows against where the token has to be verified.&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;It would be cool if other identity providers besides Cognito like Google or Okta could be used to validate the token.&lt;/p&gt;
&lt;p&gt;What is also missing are private user scopes. Those would be basically subdirectories in the private bucket which only the validated user can access. Currently, the validated users can still access all assets in the bucket.&lt;/p&gt;
&lt;p&gt;It would also be great to try Cloudfront Function instead of Lambda@Edge. Cloudfront Functions are a slimmed-down version of Lambda@Edge. They have reduced functionality and resources. But they are cheaper in general. I am very confident that Cloudfront Functions will be sufficient to validate the tokens.&lt;/p&gt;
&lt;p&gt;If you already need one of the features mentioned here or have other cool feature ideas feel free to write me or create issues directly in the Construct Repo &lt;a href=&quot;https://github.com/mmuller88/cdk-private-asset-bucket&quot;&gt;https://github.com/mmuller88/cdk-private-asset-bucket&lt;/a&gt; . You can also write PRs to get your feature implemented.&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;Private S3 assets like images or videos are almost always needed in modern apps. Until now they could only be kept private via unhandy presigned URLs. But this solution doesn&apos;t seem optimal as it doesn&apos;t use user tokens to access the assets. Here in this blog post, I presented a variant where you can make your private S3 assets available with Cognito user tokens. If you like this post or if you have any questions or suggestions, feel free to 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/31eaad727bd581abf3f078392aa8c296/bucket.jpg</featuredImage><media:content url="https://martinmueller.dev/static/31eaad727bd581abf3f078392aa8c296/bucket.jpg" medium="image"/></item><item><title><![CDATA[Deploy Lambda@Edge mit AWS CDK und TypeScript]]></title><description><![CDATA[Moin, Lambda@Edge sind Lambdas die in den AWS Cloudfront Locations ausgeführt werden. Somit kann die Performance erhöht und die Latency…]]></description><link>https://martinmueller.dev/cdk-lambda-edge/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-lambda-edge/</guid><category><![CDATA[de]]></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;Moin,&lt;/p&gt;
&lt;p&gt;Lambda@Edge sind Lambdas die in den AWS Cloudfront Locations ausgeführt werden. Somit kann die Performance erhöht und die Latency verringert werden im Vergleich zum normalen Lambda. Cloudfront zusammen mit Lambda@Edge lässt sich aber auch als Proxy für einen private S3 Asset Bucket verwenden.&lt;/p&gt;
&lt;p&gt;Ein Token ausgestellt von Cognito dient dann der Lambda@Edge zu Validierung ob der Requester erlaubt ist auf das Asset im S3 Bucket zuzugreifen. Näheres darüber möchte ich im nächsten Blogpost beschreiben. Hier soll es darum gehen wie ein Lambda@Edge mit AWS CDK und Typescript erstellt werden kann.&lt;/p&gt;
&lt;h2 id=&quot;aws-cdk-lamdaedge&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-cdk-lamdaedge&quot; aria-label=&quot;aws cdk lamdaedge permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 Lamda@Edge&lt;/h2&gt;
&lt;p&gt;Lambda@Edge gibt es bereits im 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; . Leider ist es nicht direkt möglich den Lambda Code mit TypeScript zu schreiben und automatisch nach JavaScript zu transformieren so wie wir es bereits von der &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; kennen.&lt;/p&gt;
&lt;p&gt;Tja nicht mit mir! Ich hab mir mal die NodejsFunction und die EdgeFunction genauer angeschaut und die die TypeScript Funktionalität von NodejsFunction auf die EdgeFunction übertragen. Dabei definiere ich einfach ein CDK Construct welches von EdgeFunction extended und übernehme Funktionen und Properties von der NodejsFunction. Und hier ist der Code von meinem 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;Wie ihr seht habe ich viele private Funktionen aus der NodejsFunction übernommen. Das Construct wird nun folgendermaßen in meinen CDK Stack importiert:&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;Der Lambda@Edge code verhält sich nun genauso wie wir es gewöhnt sind von der NodejsFunction. Der TypeScript Lambda-Code kann nun im src Folder mit dem Namen STACK.edge.ts angelegt werden. Benötigte third-party Libraries können bequem in der root package.json notiert werden. Webpack als module bundler sorgt dan für eine effiziente Transformierung in das JavaScript Format.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;Mega cool oder? Mit ein paar Handgriffen kann ich nun auch wie gewohnt meine Lambda@Edge in TypeScript schreiben. Natürlich plane ich den Code ins aws-cdk Repo zu kontribuierten. Hoffentlich wird mein PR dann baldig akzeptiert und ihr müsst euch nicht die Mühe machen meinen Code hier zu importieren. Findet ihr mein Construct hilfreich? Falls ja schreibt mir!&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[My first days at kreuzwerker]]></title><description><![CDATA[Hi, I have decided to go back to working with AWS full time. Even though I had a lot of fun diving into the world of Blazer and Dotnet, I…]]></description><link>https://martinmueller.dev/first-week-xw-eng/</link><guid isPermaLink="false">https://martinmueller.dev/first-week-xw-eng/</guid><category><![CDATA[de]]></category><category><![CDATA[2022]]></category><category><![CDATA[kreuzwerker]]></category><pubDate>Fri, 21 Jan 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/c8b369d49c9f6e6eb888cbf1374e9f69/title.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;I have decided to go back to working with AWS full time. Even though I had a lot of fun diving into the world of Blazer and Dotnet, I just missed working with AWS too much. So I asked around in the German AWS community if anyone else is looking for a remote AWS DevOps position. Immediately &lt;a href=&quot;https://kreuzwerker.de/&quot;&gt;kreuzwerker&lt;/a&gt; contacted me. In this post, I want to briefly describe the cool experience during the interviews and onboarding with kreuzwerker. But first, a few words about kreuzwerker.&lt;/p&gt;
&lt;h2 id=&quot;kreuzwerker&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#kreuzwerker&quot; aria-label=&quot;kreuzwerker permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;kreuzwerker&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://kreuzwerker.de/&quot;&gt;kreuzwerker&lt;/a&gt; is an AWS consulting company based in Frankfurt am Main, Berlin, Munich, Zurich and Warszawa (Poland). It was founded in 2010 by Bernd, Joern Bathel and Tilmann Eing. The main motivation to found kreuzwerker was to create a better environment for IT consultants. kreuzwerker should become a company where employees have fun at work. And as you will read they have achieved their goal!&lt;/p&gt;
&lt;h2 id=&quot;interview&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#interview&quot; aria-label=&quot;interview permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Interview&lt;/h2&gt;
&lt;p&gt;I had the interviews with Oliver and Manuel. The conversations with both of them were super cool and I immediately noticed that the company puts a lot of emphasis on a positive culture. The concept of culture and especially a positive once does not seem to be very widespread in Germany. So I will explain it briefly here. Culture means how is the living environment within the company is. For example how the employees interact with each other.&lt;/p&gt;
&lt;p&gt;This is also necessary because as an AWS consulting company, complex problems, such as designing and building technological solutions, have to be solved. And this can only be achieved if a positive culture is created in the company. That guarantees that every employee gives it best and can give.&lt;/p&gt;
&lt;p&gt;And that kreuzwerker has such a positive culture, I noticed immediately during the interviews with Oliver and Manuel. I think they also noticed that I fit in well with this culture. Yes, and indeed, appearances have not dimmed. In my first onboarding days, I was able to experience how great kreuzwerker is.&lt;/p&gt;
&lt;h2 id=&quot;onboarding&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#onboarding&quot; aria-label=&quot;onboarding permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Onboarding&lt;/h2&gt;
&lt;p&gt;In this section, I would like to tell you about my onboarding days. I had my onboarding in the Berlin kreuzwerker office. The office is very central in Berlin. Since I live a good two hours outside of Berlin and have never worked in Berlin before, I found it very exciting to come into the office.&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: 110.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAWABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMFBP/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHWpnxl1mCK1E5gf//EABoQAAMAAwEAAAAAAAAAAAAAAAABAgMREiH/2gAIAQEAAQUCnIdo7k2Oir9xvpuSsa3/AP/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABkQAAIDAQAAAAAAAAAAAAAAAAABEBExIf/aAAgBAQAGPwLqlzRrNP/EAB0QAAIBBAMAAAAAAAAAAAAAAAABESFBUWExsdH/2gAIAQEAAT8h9ZG83CmmXQ1XzgheSR4JUeyFtBcB/9oADAMBAAIAAwAAABBE4EP/xAAXEQADAQAAAAAAAAAAAAAAAAAAAREQ/9oACAEDAQE/EIiIef/EABcRAAMBAAAAAAAAAAAAAAAAAAABERD/2gAIAQIBAT8QrLv/xAAeEAEAAgIDAAMAAAAAAAAAAAABABEhQTFRYXGR8f/aAAgBAQABPxBARhOchBS4G1+5mZVYcdd7hbSKNhs8gAA0vXb5FbsFpzhLMYUrPA/kY7s+Buf/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/d23a3075b21a9f4396aacea7381d6182/f1512/berlin.webp 200w,
/static/d23a3075b21a9f4396aacea7381d6182/f59aa/berlin.webp 400w,
/static/d23a3075b21a9f4396aacea7381d6182/47a22/berlin.webp 800w,
/static/d23a3075b21a9f4396aacea7381d6182/5bb53/berlin.webp 1200w,
/static/d23a3075b21a9f4396aacea7381d6182/485a2/berlin.webp 1600w,
/static/d23a3075b21a9f4396aacea7381d6182/d5120/berlin.webp 2396w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/d23a3075b21a9f4396aacea7381d6182/16d62/berlin.jpg 200w,
/static/d23a3075b21a9f4396aacea7381d6182/27ec1/berlin.jpg 400w,
/static/d23a3075b21a9f4396aacea7381d6182/5fd6b/berlin.jpg 800w,
/static/d23a3075b21a9f4396aacea7381d6182/5a523/berlin.jpg 1200w,
/static/d23a3075b21a9f4396aacea7381d6182/b46c2/berlin.jpg 1600w,
/static/d23a3075b21a9f4396aacea7381d6182/7309a/berlin.jpg 2396w&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/d23a3075b21a9f4396aacea7381d6182/5fd6b/berlin.jpg&quot;
            alt=&quot;berlin&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 reception, I was greeted very warmly by the office manager and had a small room tour. Since we are still in the middle of the pandemic and it was also the first week in 2022, the office was less staffed. But that made it easier to remember the new names. I think names are very important and I try to keep them in my head.&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: 66.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAUCAwT/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAFlNbuGwSif/8QAGRABAAMBAQAAAAAAAAAAAAAAAgEREgMh/9oACAEBAAEFAirjUV5Q46nBgukv/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGxAAAgIDAQAAAAAAAAAAAAAAAAECIREiMZH/2gAIAQEABj8COo6i5S9NVg2Vn//EABsQAQEBAAIDAAAAAAAAAAAAAAERACExUWFx/9oACAEBAAE/IZD1xfWqkwUHAAOPGUAfnBjTpRm//9oADAMBAAIAAwAAABCgL//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAwEBPxDFf//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPxDUf//EAB0QAQACAgIDAAAAAAAAAAAAAAEAESFBUZExYXH/2gAIAQEAAT8QuIUhPjtFNCNWtg6upfGY+X3N8ClAnEbzJzo1ybjVyyTavU//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/a94749239594280f8cde72f890ac2987/f1512/xw1.webp 200w,
/static/a94749239594280f8cde72f890ac2987/f59aa/xw1.webp 400w,
/static/a94749239594280f8cde72f890ac2987/47a22/xw1.webp 800w,
/static/a94749239594280f8cde72f890ac2987/5bb53/xw1.webp 1200w,
/static/a94749239594280f8cde72f890ac2987/485a2/xw1.webp 1600w,
/static/a94749239594280f8cde72f890ac2987/04793/xw1.webp 2658w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/a94749239594280f8cde72f890ac2987/16d62/xw1.jpg 200w,
/static/a94749239594280f8cde72f890ac2987/27ec1/xw1.jpg 400w,
/static/a94749239594280f8cde72f890ac2987/5fd6b/xw1.jpg 800w,
/static/a94749239594280f8cde72f890ac2987/5a523/xw1.jpg 1200w,
/static/a94749239594280f8cde72f890ac2987/b46c2/xw1.jpg 1600w,
/static/a94749239594280f8cde72f890ac2987/bebd1/xw1.jpg 2658w&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/a94749239594280f8cde72f890ac2987/5fd6b/xw1.jpg&quot;
            alt=&quot;xw1&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;And then it was off to my first appointment with the IT staff. The IT staff explained the systems I used and handed over my hardware. I found and still find my new MacBook with the M1 chip very exciting. It has been a few years since I used a MacBook. I currently use Ubuntu exclusively. But I immediately felt happy again with the MacBook.&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: 66.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAUCAwT/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAFvFTUOTKH/xAAbEAABBQEBAAAAAAAAAAAAAAACAAEDEiEEEf/aAAgBAQABBQLF4sXQRg4zFaN7D//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABkQAAIDAQAAAAAAAAAAAAAAAAABAhARUf/aAAgBAQAGPwK1kxtnD//EABkQAQEBAQEBAAAAAAAAAAAAAAEAITFBEf/aAAgBAQABPyHXJo+NklNOBI9ybFQZ8L//2gAMAwEAAgADAAAAEPMP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQIBAT8Qh//EABsQAQEAAgMBAAAAAAAAAAAAAAERACExQXFh/9oACAEBAAE/EOSgD5hJTcyTSOk4cB8OsBv3DQsEBgYJWSIJr0z/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/3ee75a10c4078e812f62129faf80b7a9/f1512/xw2.webp 200w,
/static/3ee75a10c4078e812f62129faf80b7a9/f59aa/xw2.webp 400w,
/static/3ee75a10c4078e812f62129faf80b7a9/47a22/xw2.webp 800w,
/static/3ee75a10c4078e812f62129faf80b7a9/5bb53/xw2.webp 1200w,
/static/3ee75a10c4078e812f62129faf80b7a9/485a2/xw2.webp 1600w,
/static/3ee75a10c4078e812f62129faf80b7a9/04793/xw2.webp 2658w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/3ee75a10c4078e812f62129faf80b7a9/16d62/xw2.jpg 200w,
/static/3ee75a10c4078e812f62129faf80b7a9/27ec1/xw2.jpg 400w,
/static/3ee75a10c4078e812f62129faf80b7a9/5fd6b/xw2.jpg 800w,
/static/3ee75a10c4078e812f62129faf80b7a9/5a523/xw2.jpg 1200w,
/static/3ee75a10c4078e812f62129faf80b7a9/b46c2/xw2.jpg 1600w,
/static/3ee75a10c4078e812f62129faf80b7a9/bebd1/xw2.jpg 2658w&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/3ee75a10c4078e812f62129faf80b7a9/5fd6b/xw2.jpg&quot;
            alt=&quot;xw2&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;The following days contained usual onboarding stuff. I did online courses about security at work, with data and how to design my workstation ergonomically correct or how to use JIRA. The fancy video animations in the courses made this rather dry part quite entertaining. And actually, I learned one or two interesting things about data security :). I also find it extremely cool that there is a cook who provides us with a delicious and healthy lunch every day.&lt;/p&gt;
&lt;p&gt;I already mentioned how important a positive culture is. What fascinated me was that during my days of onboarding, I noticed this positive culture not only among the developers but also among all the other employees. I think it&apos;s so great that kreuzwerker manages to get all employees to interact positively with each other.&lt;/p&gt;
&lt;p&gt;I have already met two developers from my team. Both are still at the beginning of their career as I am already a few years ahead ^^. We had great conversations. I&apos;m impressed how far both are already in their development as developers. At the end of January, we plan to go to Frankfurt to meet the rest of the team. I&apos;m really looking forward to that.&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;The interview and the first days of onboarding at kreuzwerker were fantastic. I have briefly described here what this experience was like. I&apos;m very grateful to be part of the kreuzwerker team and, I&apos;m looking forward to working with our customers to build technical solutions they will love :). If you also want to work for kreuzwerker, feel free to contact me. See you soon :).&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/c8b369d49c9f6e6eb888cbf1374e9f69/title.png</featuredImage><media:content url="https://martinmueller.dev/static/c8b369d49c9f6e6eb888cbf1374e9f69/title.png" medium="image"/></item><item><title><![CDATA[CDK BitBucket Staging Pipeline Learnings (Teil 2)]]></title><description><![CDATA[Hi CDK folks. Vor ein paar Monaten berichtete ich euch über mein spannendes Projekt eine voll funktionsfähige CDK BitBucket Staging Pipeline…]]></description><link>https://martinmueller.dev/cdk-bitbucket-pipeline-2/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-bitbucket-pipeline-2/</guid><category><![CDATA[de]]></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;Vor ein paar Monaten berichtete ich euch über mein spannendes Projekt eine voll funktionsfähige &lt;a href=&quot;https://martinmueller.dev/cdk-bitbucket-pipeline&quot;&gt;CDK BitBucket Staging Pipeline&lt;/a&gt; zu bauen. Seit dem ist viel passiert und wir haben die Pipeline weiter entwickelt.&lt;/p&gt;
&lt;h2 id=&quot;probleme-mit-cdk-cross-stack-referenzen&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#probleme-mit-cdk-cross-stack-referenzen&quot; aria-label=&quot;probleme mit cdk cross stack referenzen permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Probleme mit CDK Cross-Stack Referenzen&lt;/h2&gt;
&lt;p&gt;CDK Cross-Stack Referenzen sind CDK Outputs die einem anderen CDK Stack als Input übergeben werden. Hier ist ein Beispiel:&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;Das Beispiel ist entnommen von &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; . Du siehst hier sehr gut wie im Producer Stack die &lt;strong&gt;myBucket&lt;/strong&gt; Variable erzeugt wird und wie der Consumer Stack darauf zugreift. Das ist eine CDK Cross-Stack Referenz. Und genau solche sind in unserem Projekt problematisch geworden.&lt;/p&gt;
&lt;p&gt;Wenn num im Producer Stack etwas geändert wird was z.B. ein Löschen und anschließendes Neuerstellen der &lt;strong&gt;myBucket&lt;/strong&gt; Variable zu folge hätte, würde Cloudformation mit einem Error antworten und ein Rollback veranlassen. Der Grund ist da der Consumer die Cross-Stack Referenz verwendet, kann diese nicht so ohne weiteres gelöscht werden. Solche und weitere Probleme haben uns das Entwickeln schwer gemacht.&lt;/p&gt;
&lt;p&gt;Wir denken und hoffen aber nun eine gute Lösung gefunden zu haben. Zu einem haben wir die Anzahl der Stacks reduziert von ungefähr 7 auf 4. Die Neuzuordnung der Services in die 4 Stacks orientiert sich nun am DDD (Domain Driven Design). Das bedeutet alle Services die zu einer Domain gehören wie z.B. der React App werden zu einem Stack gebündelt. Davor war die Aufteilung eher zufällig und orientierte sich Anhand der AWS Services wie der LambdaStack oder der CognitoStack. Nun sind die Stacks nach ihren Domaine zugeordnet und heißen FrontendSiteStack, FrontendBackendStack und MLStack.&lt;/p&gt;
&lt;p&gt;Diese neue Aufteilung hat die Anzahl der Cross-Stack Referenzen stark reduziert. So dass quasi nur noch wenige übrig geblieben sind die wir in den CommonStack ausgelagert haben. Der CommonStack dient allerdings als Parent Stack zu den drei anderen. Wenn nun nur Cross-Stack Referenzen zwischen Parent und Children Stacks herrschen, sollte das viel weniger Probleme verursachen als Referenzen zwischen Geschwister Stacks.&lt;/p&gt;
&lt;h2 id=&quot;unabhängige-stacks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#unabh%C3%A4ngige-stacks&quot; aria-label=&quot;unabhängige 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;Unabhängige Stacks&lt;/h2&gt;
&lt;p&gt;Die nächste Herausforderung war, dass die Entwickler es gerne möglich hätten die drei neuen Stacks FrontendSiteStack, FrontendBackendStack und MLStack unabhängig voneinander zu deployen. Bisher wurden alle drei immer gleichzeitig deployed.&lt;/p&gt;
&lt;p&gt;Um dieses Problem haben wir uns für &lt;a href=&quot;https://support.atlassian.com/bitbucket-cloud/docs/configure-bitbucket-pipelinesyml/&quot;&gt;Custom Variables&lt;/a&gt; entschieden. Custom Variables sind Variablen die bei Custom Pipelines beim Ausführen gesetzt werden können. Um nun die Stacks unabhänging voneinander deployen zu können, muss die Custom Pipeline mit den folgenden Variablen ausgeführt werden:&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;Startet man die cdkDeploy Pipeline mit der BitBucket UI können die drei Variablen bei bedarf auf true geändert werden. Ein simples Bash Command checkt dann ob die Variable true ist oder nicht:&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;Somit kann interaktiv über die Ausführung der Custom Pipeline und dem Setzen der Variablen der gewünschte Stack deployed werden. 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;Das Konzept einer Stage kann den CDK Code wesentlich übersichtlicher machen. Eine Stage fasst alle CDK Stacks zusammen die zu einer Stage we dev oder prod gehören. Hier ist ein Beispiel.&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;Die Stage wird nun einfach in den main.ts importiert:&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;Durch die Verwendung einer Stage Wrapper Klasse haben wir unseren Code wesentlich übersichtlicher und einfacher wartbar gestaltet.&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;Eine Staging Pipeline ist schon mal ein guter Anfang um effektiv und schnell neue Features zu entwickeln und in die Produktion zu bringen. Um allerdings noch schneller und vor allem unabhängiger von anderen Entwickler Teams entwickeln zu können, werden ephermal Deployments benötigt.&lt;/p&gt;
&lt;p&gt;Ephermal Deployments bedeutet, dass bei jedem neuen Branch potentiell eine eine komplett neues CDK Deployment ausgespielt werden kann welches die Änderungen von dem Branch beinhaltet. Somit müssen sich die Entwickler z.B. die dev Umgebung nicht mehr teilen um neue Features auszuprobieren und zu testen. Ich bin mal gespannt wie wir das machen werden.&lt;/p&gt;
&lt;p&gt;Unser React Frontend benötigt zur Buildzeit Backend Informationen die AWS Amplify typisch in einer config File gespeichert werden. Diese müssen mühselig per hand aktuell gehalten werden. Von daher wäre es cool wenn wir ähnlich wie bei der Amplify CLI es ermöglichen können, dass der Config File dynamisch vor dem Build gebaut werden kann. Unsere initiale Idee ist es, das mit AWS Api Gateway zu ermöglichen. Der Endpoint würde uns dann immer die aktuellen Backenddaten übermitteln und wir können diese als Config File speichern.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;Es macht mir immer noch Spaß mit BitBucket Pipeline zu arbeiten. Damit lassen sich tolle CDK Deployment Pipelines bauen. In diesem Post habe ich beschrieben welche neuen Herausforderungen wir hatten und wie wir sie gelöst haben. Auch sehr freut mich das mittlerweile der Kunde auch selber in der Lage ist die CDK Pipeline zu benutzen und das auch vermehrt tut.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Dankbarkeit 2021]]></title><description><![CDATA[Ein herzliches hallo, Auch dieses Jahr möchte ich wieder Danke sagen. Für das Jahr 2021 stand die Familie im Mittelpunkt. Natürlich gelten…]]></description><link>https://martinmueller.dev/thankful-2021/</link><guid isPermaLink="false">https://martinmueller.dev/thankful-2021/</guid><category><![CDATA[de]]></category><category><![CDATA[2021]]></category><category><![CDATA[notech]]></category><pubDate>Thu, 30 Dec 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/7b94a95bc98915ccbc7d0852e17c39d1/w2021.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Ein herzliches hallo,&lt;/p&gt;
&lt;p&gt;Auch dieses Jahr möchte ich wieder Danke sagen. Für das Jahr 2021 stand die Familie im Mittelpunkt. Natürlich gelten meine Danksagungen von meinen vorherigen &lt;a href=&quot;https://martinmueller.dev/thankful&quot;&gt;Post&lt;/a&gt; auch noch! In dieser Danksagung möchte ich speziell für 2021 und dessen Ereignisse Danke sagen.&lt;/p&gt;
&lt;h2 id=&quot;gott&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#gott&quot; aria-label=&quot;gott permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Gott&lt;/h2&gt;
&lt;p&gt;Auch dieses Jahr hast du Gott deine schützende Hand über uns gelegt. Du hast uns mit Gesundheit und Liebe gesegnet. Soweit sind wir von Corona verschont geblieben und ich behaupte, dass sich unserer Lebensstil durch Corona dieses Jahr nicht verändert hat. Bitte behüte uns auch in 2022. Amen.&lt;/p&gt;
&lt;h2 id=&quot;oma&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#oma&quot; aria-label=&quot;oma permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Oma&lt;/h2&gt;
&lt;p&gt;Wisst ihr wer mein zweit größtes Vorbild ist? Nun mein größtes ist Jesus. Danach kommt meine Oma Katharina Lauck. Sie ist gegen Ende November verstorben. Mit 93 Jahren und 26 Uhrenkelkindern hatte sie ein erfülltes Leben und ist nun bei ihrem Herren.&lt;/p&gt;
&lt;p&gt;Sie war immer eine tolle Oma. Allerdings erst zur ihrer Beerdigung habe ich realisiert was für ein toller Mensch sie auch war. Ich habe viele tolle Geschichten aus ihrer Vergangenheit gehört. Sie war wahrlich eine gutmütige Frau. Sie hat die Welt zu einem besseren Ort gemacht und das ist auch mein Ziel. Vielen Dank Oma für Alles. Ruhe in Frieden.&lt;/p&gt;
&lt;h2 id=&quot;frau-und-tochter&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#frau-und-tochter&quot; aria-label=&quot;frau und tochter permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Frau und Tochter&lt;/h2&gt;
&lt;p&gt;Natürlich danke ich speziell euch beiden auch wieder 2021. Wir sind sehr gesegnet mit einer gesunden Tochter und einer tollen Mami und Ehefrau. Ihr zwei habt 2021 außergewöhnlich gemacht! Durch euch zwei fühle ich mich ununterbrochen stark und bereit alle Alltagsprobleme und berufliche Herausforderungen zu meistern. Vielen lieben Dank ihr zwei.&lt;/p&gt;
&lt;h2 id=&quot;meine-mutter&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#meine-mutter&quot; aria-label=&quot;meine mutter permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Meine Mutter&lt;/h2&gt;
&lt;p&gt;Auch in diesem Jahr möchte ich speziell meiner Mutter danken. Sie ist immer für uns da wenn wir sie brauchen. Auch bin ich ihr sehr dankbar, dass wir uns immer ihr Auto ausleihen können wenn wir es brauchen. Auch wunderschön ist die starke Bindung zwischen ihr und und Rebecca (unserer Tochter). Danke dass du eine so tolle, hilfsbereite und liebenswerte Oma bist &amp;#x3C;3 .&lt;/p&gt;
&lt;h2 id=&quot;sogros-schwiegereltern&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sogros-schwiegereltern&quot; aria-label=&quot;sogros schwiegereltern permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sogros (Schwiegereltern)&lt;/h2&gt;
&lt;p&gt;Mitte Dezember sind meine Schwiegereltern aus Brasilien zu uns gekommen. Ich bin sehr dankbar dass ihr hier seid und uns so toll unterstützt. Ich freue mich auf noch zwei weitere tolle Monate mit euch. Ich hab euch ganz doll lieb :) !&lt;/p&gt;
&lt;h2 id=&quot;solarmon&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#solarmon&quot; aria-label=&quot;solarmon permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Solarmon&lt;/h2&gt;
&lt;p&gt;Aus tiefstem Herzen möchte ich Danke sagen zu meinen Ex-Kollegen aus dem Solarmon Projekt. Es war eine sehr aufregende Zeit und es hat mir viel Spaß gemacht neue Features mit Blazor und DotNet zu implementieren. Das Entwicklerteam bestand aus zwei Entwicklern und einem Produktowner.&lt;/p&gt;
&lt;p&gt;Die Entwickler waren ein Senior und ein Junior dessen Position ich inne hatte. Vor allem mit dem Senior zusammenzuarbeiten hat mir am meisten Spaß gemacht. Wir hatten tolle professionelle Diskussionen.&lt;/p&gt;
&lt;p&gt;Gegen Ende des Jahres 2021 hatte ich dann aber den schweren Entschluss gefasst mich wieder stärker auf AWS zu fokussieren. Vielen vielen Dank für die tolle Zeit und ich wünsche euch viel Erfolg für 2022 mit dem Solarmon Projekt.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;2021 war ein tolles Jahr. Auch wenn es noch viel mehr gibt wofür ich Danke sagen sollte, mache ich doch in diesem Post den Anfang. Für was seit ihr 2021 dankbar gewesen?&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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/7b94a95bc98915ccbc7d0852e17c39d1/w2021.jpg</featuredImage><media:content url="https://martinmueller.dev/static/7b94a95bc98915ccbc7d0852e17c39d1/w2021.jpg" medium="image"/></item><item><title><![CDATA[Thankfulness 2021]]></title><description><![CDATA[A warm hello, Once again this year I would like to say thank you. The center of 2021 of course was my family. Still my thanks from 2021 are…]]></description><link>https://martinmueller.dev/thankful-2021-eng/</link><guid isPermaLink="false">https://martinmueller.dev/thankful-2021-eng/</guid><category><![CDATA[de]]></category><category><![CDATA[2021]]></category><category><![CDATA[notech]]></category><pubDate>Thu, 30 Dec 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/7b94a95bc98915ccbc7d0852e17c39d1/w2021.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;A warm hello,&lt;/p&gt;
&lt;p&gt;Once again this year I would like to say thank you. The center of 2021 of course was my family. Still my thanks from &lt;a href=&quot;https://martinmueller.dev/thankful-eng&quot;&gt;2021&lt;/a&gt; are still valid! In this post I would like to say thanks specifically for 2021 and its events.&lt;/p&gt;
&lt;h2 id=&quot;god&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#god&quot; aria-label=&quot;god permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;God&lt;/h2&gt;
&lt;p&gt;This year, too, you God have laid your protective hand over us. You have blessed us with health and love. So far we have been spared from Corona and I our lifestyle has not changed due to Corona this year. Please keep us safe also in 2022. Amen.&lt;/p&gt;
&lt;h2 id=&quot;grandma&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#grandma&quot; aria-label=&quot;grandma permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Grandma&lt;/h2&gt;
&lt;p&gt;Do you know who my second biggest role model is? Well my biggest is Jesus. After that comes my grandma Katharina Lauck. She passed away at the end of November. With 93 years old and 26 great grandchildren, she had a full life and is now with her Lord.&lt;/p&gt;
&lt;p&gt;She was always a great grandma. However, it wasn&apos;t until her funeral that I realized what a great person she was also. I heard many great stories from her past. She was truly a kind-hearted woman. She made the world a better place and that is my goal as well. Thank you grandma for everything. Rest in Peace.&lt;/p&gt;
&lt;h2 id=&quot;wife-and-daughter&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wife-and-daughter&quot; aria-label=&quot;wife and daughter permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wife and daughter&lt;/h2&gt;
&lt;p&gt;Of course, I especially thank you both again 2021. We are very blessed with a healthy daughter and a great mommy and wife. You two have made 2021 extraordinary! Because of you two, I feel continuously strong and ready to face all daily problems and professional challenges. Thank you so much you two.&lt;/p&gt;
&lt;h2 id=&quot;my-mother&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-mother&quot; aria-label=&quot;my mother permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 mother&lt;/h2&gt;
&lt;p&gt;Also this year I would like to thank especially my mother. She is always there for us when we need her. I am also very grateful to her that we can always borrow her car when we need it. Also wonderful is the strong bond between her and Rebecca (our daughter). Thank you for being such a great, helpful and loving grandma &amp;#x3C;3 .&lt;/p&gt;
&lt;h2 id=&quot;sogros-parents-in-law&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sogros-parents-in-law&quot; aria-label=&quot;sogros parents in law permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sogros (Parents in law)&lt;/h2&gt;
&lt;p&gt;My parents in law from Brazil came to stay with us in the middle of December. I am very grateful that you are here and supporting us so great. I am looking forward to two more great months with you guys. I love you guys so much :) !&lt;/p&gt;
&lt;h2 id=&quot;solarmon&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#solarmon&quot; aria-label=&quot;solarmon permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Solarmon&lt;/h2&gt;
&lt;p&gt;From the bottom of my heart I want to say thank you to my ex-colleagues from the Solarmon project. It was a very exciting time and I had a lot of fun implementing new features with Blazor and DotNet. The development team consisted of two developers and a product owner.&lt;/p&gt;
&lt;p&gt;The developers were a senior and a junior whose position I held. I especially enjoyed working with the senior the most. We had great professional discussions.&lt;/p&gt;
&lt;p&gt;Towards the end of 2021, however, I had made the tough decision to focus more on AWS technologies again. Thank you very much for the great time and I wish you all the best for 2022 with the Solarmon 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;2021 was a great year. Even though there is a lot more I should say thanks for, I&apos;ll make a start in this post. What were you thankful for in 2021?&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://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/7b94a95bc98915ccbc7d0852e17c39d1/w2021.jpg</featuredImage><media:content url="https://martinmueller.dev/static/7b94a95bc98915ccbc7d0852e17c39d1/w2021.jpg" medium="image"/></item><item><title><![CDATA[Asynchrone Kommunikation mit AWS CDK EventBridge]]></title><description><![CDATA[Hallo CDK Fans Für ein Startup soll ich eine Security Plattform bauen. Der grobe Ablauf zur Benutzung der Plattform ist in etwa so. Der…]]></description><link>https://martinmueller.dev/cdk-eventbridge/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-eventbridge/</guid><category><![CDATA[de]]></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;Hallo CDK Fans&lt;/p&gt;
&lt;p&gt;Für ein Startup soll ich eine Security Plattform bauen. Der grobe Ablauf zur Benutzung der Plattform ist in etwa so. Der Kunde beantwortet ein paar Fragen und bekommt dann eine Security Auswertung angezeigt. Für den Prototypen habe ich mich entschieden AWS EventBridge zu benutzen. Damit erreiche ich eine Entkopplung und asynchrone Verarbeitung der Services zu einander, zu gewährleisten.&lt;/p&gt;
&lt;p&gt;Das war das erste mal, dass ich EventBridge verwendet habe und ich bin sehr begeistert. Da es noch nicht all zu viel AWS CDK EventBridge Material im Internet gibt, wollte ich dich gerne an meiner Experience teilhaben lassen.&lt;/p&gt;
&lt;p&gt;Nachfolgend beschreibe ich die Security Plattform etwas genauer und wie meine Architektur aussieht.&lt;/p&gt;
&lt;h2 id=&quot;security-plattform&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#security-plattform&quot; aria-label=&quot;security plattform permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 Plattform&lt;/h2&gt;
&lt;p&gt;Der Nutzer kann mittels Desktop App oder Mobile App einige Fragen beantworten. Die Antworten werden im User-Service gespeichert und asynchron an den Security-Service geschickt. Ist die Verarbeitung im Security-Service fertig, bekommt der Nutzer das Ergebnis als Report präsentiert.&lt;/p&gt;
&lt;h2 id=&quot;architektur&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#architektur&quot; aria-label=&quot;architektur permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Architektur&lt;/h2&gt;
&lt;p&gt;Der Prototyp hat drei Module. Diese drei Module sind jeweils mit ihrem eigenen CDK Stack implementiert. Das ist das Frontend, der User-Service und der 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;Das Frontend ist eine ReactTS App welches in S3 via static Webhosting gehosted wird. Die App nutzt Amplify Libraries zum Usermanagement wie Sign up, Password wiederherstellen, Login, Logout. Auch nutze ich Amplifies GraphQl Libraries als typisierten Zugriff auf das AppSync im User-Service. Schau auch gerne in meine anderen Beiträge über &lt;a href=&quot;https://martinmueller.dev/tags/appsync&quot;&gt;Appsync&lt;/a&gt; rein.&lt;/p&gt;
&lt;p&gt;Der Nutzer soll nach dem Einloggen eine Reihe von Security Fragen beantworten. Die Antworten werden über GraphQL Queries an den User-Service geleitet. Darüber hinaus besitzt das Frontend noch eine Liste von Security Reports welche von dem Security-Service erstellt wurde.&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;Die Antworten werden nun im AppSync verarbeitet und in eine Antworten DynamoDB Tabelle gespeichert. Von dort aus lauscht eine DynamoDB Stream Lambda auf neue oder geänderte Antworten. Die Lambda schreibt dann die Antwort als &lt;strong&gt;AntwortEvent&lt;/strong&gt; in den EventBridge EventBus. Der EventBus leitet das AntwortEvent weiter an den Security-Service.&lt;/p&gt;
&lt;p&gt;Nachdem der Security-Service das AntwortEvent verarbeitet hat sendet dieser ein &lt;strong&gt;ReportEvent&lt;/strong&gt; an den User-Service via den EventBus zurück. Eine Report Lambda im User-Service erhält dann das ReportEvent und schreibt den Report via GraphQL Mutation in eine Report DynamoDB Tabelle.&lt;/p&gt;
&lt;p&gt;Das Frontend besitzt eine GraphQl Subscription für neu erscheinende Reports und somit wird die Liste der Reports automatisch geupdated sofern ein neuer Report gespeichert wird.&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;Der Security-Service erhält ein AntwortEvent vom User-Service mittels EventBus von EventBridge. Das AntwortEvent ist ein Wrapper und enthält neben der Antwort selbst noch Eventdaten wie Created, Updated, Status. Eine Report Lambda empfängt dann die Antwort und verarbeitet diese zu einem Report. Anschließend wird der Report in ein ReportEvent gepackt und zurück an den User-Service gesendet.&lt;/p&gt;
&lt;p&gt;Noch reicht es für die Erstellung des Reports eine Lambda zu verwenden. Das könnte sich in Zukunft aber auch ändern da der Report komplexer werden soll und z.B. auch third party APIs verwenden soll. Dann könnte ein etwas komplexerer Workflow anstehen. Mit der Verwendung dieser Eventarchitektur sollte das aber kein Problem werden.&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;Zum senden der Events zwischen dem User-Service und dem Security-Service benutze ich den default EventBus. Das AnswerEvent und ReportEvent sehen so aus:&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;Interessant hier ist vielleicht dass ich für die Definition der Events einfach auf die von AppSync generierten GraphQL Wrapper Klassen im Frontend zurückgreife unter ../frontend/src/lib/api.&lt;/p&gt;
&lt;p&gt;Nun definiert man noch die Lambdas welche das jeweilige Event in den default EventBus packen. Hier z.B. die Lambda welche das AntwortEvent in den EventBus packt.&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;Im EventStack müssen dan noch sogenannte Rules und Targets definiert werden.&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;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;Services asynchron miteinander kommunizieren zu lassen ist mega toll und aufregend. Mit AWS EventBridge und AWS CDK ist es zusätzlich noch eine wundervolle Developer Experience. Ich bin sehr gespannt wo sich die Security Plattform noch hinentwickelt :).&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Eine CDK BitBucket Staging Pipeline]]></title><description><![CDATA[Seit einiger Zeit arbeite ich für einen Kunden mit sehr aufregenden AWS CDK Aufgaben. Der Kunde ist stark im Atlassian Ecosystem unterwegs…]]></description><link>https://martinmueller.dev/cdk-bitbucket-pipeline/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-bitbucket-pipeline/</guid><category><![CDATA[de]]></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;Seit einiger Zeit arbeite ich für einen Kunden mit sehr aufregenden AWS CDK Aufgaben. Der Kunde ist stark im Atlassian Ecosystem unterwegs. Zum hosten des Codes wird BitBucket verwendet. Nun will der Kunde stärker in den DevOps Bereich vordringen und seine AWS Deployments auch mit AWS CDK managen. Dafür soll die vorhandene AWS Infrastruktur in CDK übersetzt werden. Zusätzlich soll eine Staging Deployment-Pipeline die CDK Apps auf den Stages dev, qa und prod deployen. Gerne helfe ich da weiter :).&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;Auch wenn ich bereits sehr viel Erfahrung mit CDK habe (siehe &lt;a href=&quot;https://martinmueller.dev/tags/cdk&quot;&gt;hier&lt;/a&gt;), kenne ich mich so noch gar nicht mit BitBucket aus. Von daher weiß ich nicht ob mein Ansatz der ideale ist, aber zum Zeitpunkt des Schreibens dieses Artikels, funktioniert dieser ganz gut :).&lt;/p&gt;
&lt;p&gt;Ich schreibe diesen Artikel hauptsächlich da ich keine anderen hilfreichen Posts oder Anweisungen gefunden habe, wie man vernünftig eine CDK Staging Deployment-Pipeline baut mit BitBucket. Falls du also vielleicht eine ähnliche Aufgabe hast, kann ich dir damit den Einstieg eventuell erleichtern.&lt;/p&gt;
&lt;h2 id=&quot;welche-pipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#welche-pipeline&quot; aria-label=&quot;welche 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;Welche Pipeline?&lt;/h2&gt;
&lt;p&gt;Nun stellte sich natürlich die frage wo soll die CDK Staging Deployment-Pipeline denn leben? Zu Auswahl standen AWS CodePipeline oder BitBucket&apos;s Pipeline.&lt;/p&gt;
&lt;h2 id=&quot;vielleicht-aws-codepipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#vielleicht-aws-codepipeline&quot; aria-label=&quot;vielleicht 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;Vielleicht AWS CodePipeline?&lt;/h2&gt;
&lt;p&gt;Der Vorteil von AWS CodePipeline wäre das es dafür schon geniale AWS CDK Staging Pipeline Construct gibt wie z.B. der &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/pipelines-readme.html&quot;&gt;CDK Pipeline&lt;/a&gt; . Damit hätte man fast alles was das DevOps Herz begehrt z.B. eine Synth Action wobei aus CDK das Cloudformation template generiert wird und Deploy Actions die dann zu den jeweiligen Stages deployen. Auch mega genial von der CDK Pipeline sind die optionalen Actions die nach dem Deploy zu einer Stage ausgeführt werden können. Damit können z.B. Integrations Tests nach dem Deploy ausgeführt werden. Auch sehr schön ist, dass die Pipeline in TypeScript definiert ist und z.B. somit eine Dokumentation mitliefert und durch die Types einen gewissen Standard ja bereits schon vorgibt.&lt;/p&gt;
&lt;h2 id=&quot;oder-bitbuckets-pipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#oder-bitbuckets-pipeline&quot; aria-label=&quot;oder 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;Oder BitBucket&apos;s Pipeline?&lt;/h2&gt;
&lt;p&gt;Der Kunde verwendet bereits BitBucket&apos;s Pipeline zum Testen, Linten und dem Erstellen von Builds. Von daher wäre es unschön wenn der Kunde gezwungen wäre zwischen den zwei Pipeline Dashboards AWS CodePipeline und BitBucket&apos;s Pipeline hin und her zu schalten. Außerdem lassen sich prinzipielle ja alle Funktionen von der AWS CodePipeline und dem CDK Pipeline Construct ja quasi nach programmieren mit BitBucket&apos;s Pipeline.&lt;/p&gt;
&lt;p&gt;Ein ziemlich cooles Feature welches AWS CodePipeline nicht hat, ist das Skippen von Steps falls das angegebene Subdirectory nicht geändert wurde. Hier ist ein Beispiel:&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;So ein cooles Feature vermisse ich bei AWS CodePipeline. Auch verwendet der Kunde ein Monorepo. Es sind also alle Projekte in einem BitBucket Repository. Das wäre auch sehr Nachteilig für AWS CodePipeline da dieses ja immer bei jedem Commit einen Pipeline Run auslösen würde.&lt;/p&gt;
&lt;p&gt;Unter Berücksichtigung aller Vor- und Nachteile haben wir uns für BitBuckets&apos;s Codepipeline als CDK Staging Deployment-Pipeline entschieden.&lt;/p&gt;
&lt;h2 id=&quot;ordnerstruktur&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ordnerstruktur&quot; aria-label=&quot;ordnerstruktur permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ordnerstruktur&lt;/h2&gt;
&lt;p&gt;Wie bereits gesagt, der Kunde hat ein Monorepo und das möchte dieser natürlich beibehalten. Wir haben uns nun für die folgender Ordnerstruktur entschieden:&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 ist entweder dev, qa oder prod .&lt;/p&gt;
&lt;p&gt;Im &lt;strong&gt;devops&lt;/strong&gt; Ordner befinden sich die AWS CDK dependencies. Via package.json werden alle benötigten CDK Libraries geladen z.B. :&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.129.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.129.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.129.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.129.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;Auch beinhaltet die devops/package.json ein Script zum bootstrap des Build AWS Accounts und des Synthetisierens. Der Build AWS Account ist der Account von wo aus die Stages verwaltet werden. Synthetisieren bezeichnet man den Prozess bei der die CDK App in ein oder mehrere Cloudformation Templates überführt wird:&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 string-property 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 operator&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token string-property 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 string-property 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;Der Bootstrap command erzeugt einen CDK Helper Stack im Build Account 44444444 und trusted allen Stages dev = 11111111, qa = 222222, prod = 3333333. Trusted meint hier das der CDK Helper Stack Role eine Cross Account Deploy Erlaubnis hinzugefügt wird. Damit kann der Build Account in die verschiedenen Stage Accounts deployen. Sehr wichtig ist auch, dass jeweils die Stage Accounts einen Bootstrap durchführen müssen. Der Bootstrap command befindet sich dann jeweils in devops/${STAGE}/package.json z.B. für dev:&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 string-property 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 operator&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token string-property 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://$11111111/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;Wie man hier sieht muss auch umgekehrt der Stage Account z.b. dev=11111111 dem Build Account 44444444 trusten. Diese Bootstraps können etwas verwirrend sein, müssen aber zum Glück nicht oft durchgeführt werden. Ich empfehle trotzdem den Bootstrap Prozess gut zu dokumentieren in z.B. der Readme.md . Generell halte ich eine gute Dokumentation für sehr sehr hilfreich :).&lt;/p&gt;
&lt;h2 id=&quot;beispiel-vpc&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#beispiel-vpc&quot; aria-label=&quot;beispiel 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;Beispiel VPC&lt;/h2&gt;
&lt;p&gt;In jeder Stage soll es ein VPC geben in der private Infrastruktur wie Postgres DBs deployed werden sollen. Jede Stage beinhaltet also ein VPC subdirectory devops/${STAGE}/vpc . Dort in einer main.ts befindet sich der CDK Code. Ich zeige das hier anhand von der 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;Da jede Stage einen VPC benötigt, macht es Sinn den gemeinsamen VPC CDK Code in eine shared Componente zu platzieren under dem Ordner devops/components :&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;In devops/src/main.ts wird dann das jeweilige VPC geladen:&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;Zugegeben die künstliche Aufteilung der Stages in devops/${STAGE}/vpc und anschließendem Zusammenführen in devops/src/main.ts ist etwas komisch und eventuell nicht ideal. Alternativ könnte auch einfach alles in devops/src/main.ts geschrieben werden. Wir erhoffen uns so aber eine bessere Übersichtlichkeit über die &quot;einzelnen&quot; CDK stacks.&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;Die Bitbucket Pipeline durchläuft nun grob die folgenden Schritte. Zuerst werden parallel Tests durchlaufen und Builds gebaut. Unter den Builds sind z.B. auch verschiedene React Builds für die verschiedenen Stages. Danach wird der CDK synth mittels &lt;code&gt;yarn cdk synth&lt;/code&gt; durchgeführt. Beim synth werden Assets wie z.B. die verschiedenen React Builds in S3 geuploaded:&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;Nach dem synth kann nun die erste Stage dev die per CDK synthetisierten Cloudformation Templates anwenden. Dafür benutze ich z.B. diesen 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;Der cdk.out Ordner wurde vorher beim CDK synth step als Artifact ausgewiesen und wird nun für die jeweiligen Stages (hier dev) und CDK stacks wiederverwendet. Der Pipeline yaml Code sieht folgendermaßen aus:&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;Es wird also direkt in die dev Stage deployed. Dabei wird auch parallel ein diff zur nächsten Stage qa erzeugt. Um auch den qa deploy durchzuführen, muss via manual trigger beim &lt;strong&gt;Approval deploy qa&lt;/strong&gt; step zugestimmt werden. Stimmt man zu läuft der ganze Prozess in qa analog zu dev ab.&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;Im Sinne der Übersichtlichkeit fehlt uns noch eine Art Dashboard um die wichtigsten CfnOutput URLs anzuzeigen wie z.B. die Cloudfront Urls von den React Apps. Auch will man ja wissen welcher Commit bei dem jeweiligen Deploy verwendet wurde. Dafür würde sich sehr gut ein Dashboard eignen welches per Lambda die aktuellen Deployments sowie deren Commit ID herausfinden und wahrscheinlich auch direkt darstellen kann.&lt;/p&gt;
&lt;h2 id=&quot;zusammenfassung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zusammenfassung&quot; aria-label=&quot;zusammenfassung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zusammenfassung&lt;/h2&gt;
&lt;p&gt;Mit BitBucket als Repository zu arbeiten, war mega cool. Es hat mir viel Spaß gemacht unter diesen Umständen eine CDK Staging Deployment-Pipeline zu bauen. Hier habe ich grob beschrieben wie diese Pipeline aussieht und was unsere Gründe waren diese Pipeline so zu bauen. Ob das gute Entscheidungen waren wird die Zukunft zeigen wenn der Kunde die Pipeline auch tatsächlich benutzt. Glaubst du wir haben etwas übersehen oder du hast Ideen was man besser machen kann? Dann schreibe mir doch bitte :).&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 und Hardening Checks mit der Prowler AMI]]></title><description><![CDATA[Prowler Video
(Click me :D) Hi Leute! Entwickeln in AWS macht Spaß und die Möglichkeiten coole Sachen zu bauen, scheinen unendlich. Aber…]]></description><link>https://martinmueller.dev/prowler-ami/</link><guid isPermaLink="false">https://martinmueller.dev/prowler-ami/</guid><category><![CDATA[de]]></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 Leute!&lt;/p&gt;
&lt;p&gt;Entwickeln in AWS macht Spaß und die Möglichkeiten coole Sachen zu bauen, scheinen unendlich. Aber sind diese tollen Sachen sicher und folgen sie AWS&apos;s Best Practices? Mit der &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-jlwcdlc3weta6&quot;&gt;Prowler AMI&lt;/a&gt; kannst du du mit weit über 180 Checks für viele Services in all deinen Regionen genau das überprüfen. Für nur $1 erstellt dir eine Ec2 Instanz, gestartet mit der Prowler AMI, den &lt;a href=&quot;https://github.com/mmuller88/cdk-prowler&quot;&gt;cdk-prowler&lt;/a&gt; in deinen Account. Dabei wird automatisch ein CodeBuild gestartet der die Checks ausführt. Am Ende erhältst du eine Auswertung der Checks. Die Auswertung enthält Angaben ob der Check erfolgreich war, die Severity, eine Risikobeschreibung und wie Abhilfe geschaffen werden kann.&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;Im nächsten Abschnitt erkläre ich wie genau Prowler die Checks durchführt.&lt;/p&gt;
&lt;h1&gt;Prowler Scan&lt;/h1&gt;
&lt;p&gt;Die Prowler AMI verwendet das Github &lt;a href=&quot;https://github.com/toniblyx/prowler&quot;&gt;Prowler Tool&lt;/a&gt;. Wenn ihr lokal Prowler mal ausprobieren wollt, verwendet die Anweisungen aus der &lt;a href=&quot;https://github.com/toniblyx/prowler#requirements-and-installation&quot;&gt;Readme&lt;/a&gt;. Prowler kann dann wahlweise als Script mit &lt;code&gt;./prowler&lt;/code&gt; oder als Docker Container ausgeführt werden. Prinzipiell durchläuft Prowler dann die Checks mit der AWS CLI aus dem &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;Nach dem Durchlauf der Checks wird ein HTML Report in einen S3 Bucket mit Namen prowleraudit-stack-prowlerauditreportbucket gespeichert (siehe Bild von oben). Der HTML Report listet nun alle Findings der durchgeführten Checks auf. Diese können seit kürzlich releasten Prowler Version 2.5.0 nun auch gefiltert werden.&lt;/p&gt;
&lt;h1&gt;Run Prowler mit AMI&lt;/h1&gt;
&lt;p&gt;Wie Eingangs erwähnt könnt ihr Prowler mit meiner &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-jlwcdlc3weta6&quot;&gt;Prowler AMI&lt;/a&gt; in euren Account deployen. In diesen Abschnitt erkläre ich euch wie genau das geht.&lt;/p&gt;
&lt;p&gt;Zuerst klickt ihr natürlich auf den &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-jlwcdlc3weta6&quot;&gt;Prowler AMI&lt;/a&gt; Link und subscribed zu der AMI. Das Subscriben dauert einen kleinen Moment. Nachdem die Subscription abgeschlossen ist klickt auf &quot;Continue to Configure&quot;. Wählt dort nun die neueste Prowler Version aus und die Region in der ihr die Prowler Checks durchführen wollt. Anschließend klickt auf &quot;Continue to Launch&quot;. Nun ganz wichtig bei &quot;Choose Action&quot; müsst ihr &quot;Launch through Ec2&quot; auswählen. Nun werdet ihr auf Ec2 in der AWS Console weitergeleitet.&lt;/p&gt;
&lt;p&gt;Einfach den vorausgewählten Instance Typen auswählen welcher t2.micro sein sollte. Dann auf &quot;Next: Configure Instance Details&quot; klicken. Nun ganz wichtig! Bei der IAM role braucht ihr eine Ec2 Role die Administrator Privilege hat. Falls die Role noch nicht existiert klickt auf &quot;Create new IAM role&quot; und erstellt eine AWS service Role für Ec2 mit der AdministratorAccess Policy. Die Prowler AMI braucht diese Permission um den CDK stack bei euch deployen zu dürfen.&lt;/p&gt;
&lt;p&gt;Alternativ könnt ihr Prowler auch direkt über die Ec2 AWS Console aufrufen. Dafür einfach in der AWS Console auf Ec2 wechsel --&gt; Instances --&gt; Launch Instances und sucht dann nach Prowler. Der Rest verhält sich genauso wie im vorherigen Abschnitt beschrieben.&lt;/p&gt;
&lt;p&gt;Nun wird der Prowler Cloudformation Stack deployed und der Prowler Check mittels CodeBuild gestartet. Am ende landet der HTML Report im S3 Bucket prowleraudit-stack-prowlerauditreportbucket .&lt;/p&gt;
&lt;p&gt;Die Ec2 Instanz wird nur zum deployen des Cloudformation Stacks benötigt und sollte nach Fertigstellung des Stacks terminiert werden um Kosten zu sparen.&lt;/p&gt;
&lt;h1&gt;Rerun Prowler mit AMI&lt;/h1&gt;
&lt;p&gt;Um erneut den Prowler Scan durchzuführen, müsst ihr einfach die AMI bzw. die Ec2 Instanz mit der AMI nochmal ausführen. Der Prowler Stack wird somit veranlasst den Scan nochmal durchzuführen.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Prowler ist ein tolles Tool zum überprüfen des AWS Accounts. Mit weiter über 100 Checks gibt es mir nützliches Feedback über Einstellungen die nicht Best Practices entsprechen. Somit erreiche ich eine höhere Sicherheit in meinen AWS Accounts. Mit meiner &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-jlwcdlc3weta6&quot;&gt;Prowler AMI&lt;/a&gt; ist es dazu noch kinderleicht das Tool im Account auszuführen. Probiert gerne die Prowler AMI aus und berichtet mir eure Erfahrung :).&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Automatisiertes AWS Security Feedback mit Prowler und AWS CDK]]></title><description><![CDATA[Hi Leute! Toni De La Fluente hat das super coole AWS Security Tool Prowler entwickelt. Prowler ist ein cli tool für die Durchführung und…]]></description><link>https://martinmueller.dev/prowler-cdk/</link><guid isPermaLink="false">https://martinmueller.dev/prowler-cdk/</guid><category><![CDATA[de]]></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 Leute!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/ToniBlyx&quot;&gt;Toni De La Fluente&lt;/a&gt; hat das super coole AWS Security Tool &lt;a href=&quot;https://github.com/toniblyx/prowler&quot;&gt;Prowler&lt;/a&gt; entwickelt. Prowler ist ein cli tool für die Durchführung und Beratung von AWS Security Assessment, Auditing, Hardening and Incident Response. Mit mehr als 180 checks bietet Prowler dabei das umfangreichste Security Check Angebot für AWS. Wenn ihr mehr über Prowler wissen wollt besucht die &lt;a href=&quot;https://github.com/toniblyx/prowler&quot;&gt;Prowler Github&lt;/a&gt; Seite.&lt;/p&gt;
&lt;p&gt;Ich benutze Prowler sehr viel und habe mich entschlossen dafür ein AWS CDK Custom Construct zu schreiben. In der Vergangenheit habe ich schon einige Custom Constructs erstellt wie meinem Favoriten der &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-staging-pipeline&quot;&gt;staging pipeline&lt;/a&gt; oder der &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;Falls ihr Prowler aber einfach nur für euren AWS Account ausführen möchtet und nicht das Custom Construct ausprobieren wollt, habe ich eine gute Nachricht. Für dem AWS Marketplace habe ich eine AMI erstellt welche das cdk-prowler construct automatisch in deinen Account installiert. Die AMI ist erhältlich im AMI Store. Dafür einfach nach Prowler suchen oder ihr nutzt den &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;Dann führt Prowler den Security Check durch und ihr findet die Security Findings in einem S3 Bucket mit Namen prowleraudit-stack-prowlerauditreportbucket den 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;Oder auch in der 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;Falls ihr irgendwelche Probleme mit der AMI haben solltet, bitte schreibt mir.&lt;/p&gt;
&lt;p&gt;Mit dem Kauf der AMI unterstützt ihr auch meine freie Arbeit zur Erstellung solcher frei erhältlichen Produkte wie dem &lt;a href=&quot;https://github.com/mmuller88/cdk-prowler&quot;&gt;cdk-prowler&lt;/a&gt;  custom construct und die Arbeit an meinen Blogpost. Vielen herzlichen Dank :)!&lt;/p&gt;
&lt;p&gt;In den nächsten Abschnitten erkläre ich warum ich denke, dass ein CDK Custom Construct nützlich ist und und stelle euch das cdk-prowler Custom Construct vor. Vorweg muss ich aber erstmal erklären was AWS CDK überhaupt ist.&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; ist ein Open Source Framework zu Erstellung und Verwaltung von AWS Ressourcen. Durch die Verwendung von dem Entwickler vertrauten Sprachen wie TypeScript oder Python wird die Infrastructure as Code beschrieben. Dabei synthetisiert CDK den Code zu AWS Cloudformation Templates und kann diese optional gleich deployen.&lt;/p&gt;
&lt;p&gt;AWS CDK erfährt seit 2019 ein stetigen Zuwachs von begeisterten Entwicklern und hat bereits eine starke und hilfsbereite Community die eg. sehr auf &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt; aktiv ist. Es gibt natürlich noch viel mehr zu sagen über AWS CDK und ich empfehle euch es zu erforschen. Schreibt mir, wenn ihr Fragen habt.&lt;/p&gt;
&lt;h1&gt;Motivation&lt;/h1&gt;
&lt;p&gt;AWS CDK Custom Constructs sind quasi eigene Library zum kapseln von Cloudformation Ressourcen. Diese können auf Registries wie npmjs.com oder pypi.org zum download Angeboten werden. Somit ist es extrem einfach cdk-prowler in seine CDK IDE Umgebung zu integrieren. Auch ist es sehr leicht Änderungen am cdk-prowler code durchzuführen und eine neue Version den jeweiligen Restries bereitzustellen. Vieles von diesen wichtigen aber doch mühseligen Arbeiten wird bereits durch &lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen AwsCdkConstructLibrary&lt;/a&gt; stark vereinfacht.&lt;/p&gt;
&lt;p&gt;Ein weiterer Grund für das Custom Construct ist die &lt;a href=&quot;https://github.com/aws/jsii&quot;&gt;Jsii&lt;/a&gt; Library. Mit dieser mega coolen Library kann ich das cdk-prowler construct zu verschiedene Sprachen wie Python, Java oder CSharp übersetzen und der Entwickler kann weiterhing in seiner gewohnten CDK Sprache mit cdk-prowler entwickeln.&lt;/p&gt;
&lt;h1&gt;Beispiel&lt;/h1&gt;
&lt;p&gt;Das cdk-Prowler Construct ist auf &lt;a href=&quot;https://github.com/mmuller88/cdk-prowler&quot;&gt;GitHub&lt;/a&gt;. Es muss zuerst in der package.json als Dependency eingebunden werden und kann dann im CDK Stack verwendet werden.&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;Der AWS CDK Code zeigt wie leicht cdk-prowler deployed werden kann. Viele Zusatzfunktionen wie einem Scheduler sind bereits erhältlich und über die Properties aktivier- und änderbar . Schaut dafür doch gerne in die &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;Ausblick&lt;/h1&gt;
&lt;p&gt;Viele coole Features für cdk-prowler sind geplant. Die Entwicklung neuer Features geschieht in Zusammenarbeit mit &lt;a href=&quot;https://twitter.com/ToniBlyx&quot;&gt;Tony De La Fluente&lt;/a&gt; dem Erfinder von Prowler.&lt;/p&gt;
&lt;p&gt;Geplant ist Prowler Multiaccount ready zu machen. Somit hat man dann einen zentralisierten Ort für Prowler um alle Accounts überprüfen zu können. Multiaccount soll mit und ohne AWS Organisation funktionieren.&lt;/p&gt;
&lt;p&gt;Zukünftig soll der Prowler nicht mehr mit Codebuild sondern mit Fargate ausgeführt werden. Das ermöglicht eine flexiblere Weiterentwicklung von Prowler um z.B. Scans zu parallelisieren. Die Prowler Scans zu parallelisieren ist ein wichtiges und sehr benötigtes Feature da mit über 180 Prowler Tests die sequentiell ausgeführt werden, die Ausführung sehr lange dauern kann.&lt;/p&gt;
&lt;p&gt;Auch denken Tony und ich über eine verbessertes UI Analyse Tool mit QuickSight nach. Der Prowler HTML Report ist zwar sehr nützlich aber es ist schwer komplexe Abfragen and den Report zu schicken. Mit QuickSight hat man z.B. die Möglichkeit zur Definition von Filtern, Variablen usw.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Prowler ist mega cool und ich liebe es, dass es mir automatisiert Feedback über Security, Best Practises usw. gibt. Mit AWS CDK lässt sich ProwlerAudit leicht installieren und mit anderen Services verschachteln. Testet das ProwlerAudit Construct und gebt mir Vorschläge um es noch cooler zu machen. Gerne könnt ihr dafür auch PRs in Github erstellen.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 Beiträge automatisieren mit AWS CDK]]></title><description><![CDATA[Hi Leute! In meinem letzten Post ging es darum wie ich ein Wordpress Deployment mit Docker und ein paar coolen Scripts, DevOps freundlicher…]]></description><link>https://martinmueller.dev/wp-post-automation-cdk/</link><guid isPermaLink="false">https://martinmueller.dev/wp-post-automation-cdk/</guid><category><![CDATA[de]]></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 Leute!&lt;/p&gt;
&lt;p&gt;In meinem &lt;a href=&quot;https://martinmueller.dev/wordpress-with-docker&quot;&gt;letzten Post&lt;/a&gt; ging es darum wie ich ein Wordpress Deployment mit Docker und ein paar coolen Scripts, DevOps freundlicher gestalten kann. Heute soll es um eine andere spannende Aufgabe gehen. Undzwar möchte der Kunde, dass mittels AWS und beim Hochladen von Videos zu S3, automatisch neue Wordpress Beiträge erzeugt werden. Das klingt nach einer spannenden Aufgabe. In den nächsten Abschnitten beschreibe ich meine Lösung.&lt;/p&gt;
&lt;h1&gt;Wordpress AWS Lösung&lt;/h1&gt;
&lt;p&gt;Wie oben beschrieben möchte ich, dass nach dem Video Upload zu S3 ein Wordpress Beitrag erstellt wird. Und natürlich soll das Video dann in dem Post eingefügt sein. Dafür brauche ich hauptsächlich die zwei AWS Services S3 und Lambda. Das Lambda muss dann so eingestellt werden, dass bei einem Upload zu S3 die Lambda Logik ausgeführt wird.&lt;/p&gt;
&lt;p&gt;Das Lambda soll sich dann mittels SSH in die Wordpress Umgebung einloggen und per &lt;a href=&quot;https://developer.wordpress.org/cli/commands/post/create/&quot;&gt;WP CLI&lt;/a&gt; einen neuen Beitrag erstellen. Ich finde es ziemlich cool, dass Wordpress eine eigene CLI hat. Mit dieser kann ich dann z.B. einfach neue Beiträge erstellen.&lt;/p&gt;
&lt;p&gt;Die Konfiguration der AWS Services mache ich mit AWS CDK. Den kompletten Code findet ihr in meinem Github Repo &lt;a href=&quot;https://github.com/hacking-akademie/video-up&quot;&gt;hier&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; ist ein Open Source Framework zu Erstellung und Verwaltung von AWS Ressourcen. Durch die Verwendung von dem Entwickler vertrauten Sprachen wie TypeScript oder Python wird die Infrastructure as Code beschrieben. Dabei synthetisiert CDK den Code zu AWS Cloudformation Templates und kann diese optional gleich deployen.&lt;/p&gt;
&lt;p&gt;AWS CDK erfährt seit 2019 ein stetigen Zuwachs von begeisterten Entwicklern und hat bereits eine starke und hilfsbereite Community die eg. sehr auf &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt; aktiv ist. Es gibt natürlich noch viel mehr zu sagen über AWS CDK und ich empfehle euch es zu erforschen. Schreibt mir, wenn ihr Fragen habt.&lt;/p&gt;
&lt;p&gt;Der Wordpress S3 Lambda Stack sieht nun folgendermaßen aus:&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;Bei der Lambda habe ich mich für das &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; entschieden weil es mit vielen Vorteilen kommt wie esbuild als Packagemanager und ich somit keine separate package.json für die Lambda erstellen muss da esbuild sich den benötigten Library Code aus der Haupt package.json zusammensucht.&lt;/p&gt;
&lt;p&gt;Das ssh2 Modul für die Lambda muss allerdings als external Modul geladen werden. Das bedeuted einfach, dass esbuild hierfür nicht als packagemanager verwendet wird und das Modul komplett geladen wird.&lt;/p&gt;
&lt;p&gt;Der Code für die Lambda Function wird im nächsten Abschnitt gezeigt und erklärt.&lt;/p&gt;
&lt;h1&gt;Lambda&lt;/h1&gt;
&lt;p&gt;Die Lambda hat als Event Source den S3 Bucket und wird beim Erstellen von Objekten im S3 Bucket ausgeführt. Dann verbindet sich die Lambda mit dem Wordpress Hoster über SSH und erstellt einen Wordpress Beitrag mittels &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;// DateiName: LektionID_KategorieID_Titel&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;Wie ihr sehen könnt verwende ich die NodeSSH Klasse vom node-ssh package um mich zu dem wordpress Hoster zu verbinden. Dann pare ich einige Informationen vom S3 Objekt Key wie dem Titel oder die Lektion. Am Schluss erstelle ich einfach mit der WP CLI die wordpress Beiträge.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Die Erstellung von Wordpress Beiträgen mittels AWS Services zu automatisieren ist einfach mega cool. Dafür habe ich einen kleinen AWS CDK Stack gebaut. Ich bin schon sehr gespannt was sich eventuell noch in Wordpress automatisieren lässt :). Habt ihr vielleicht eine Idee? Dann schreibt mir!&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 mit Docker]]></title><description><![CDATA[Hi Leute! Für meinen neusten Kunden habe ich ein tolles AWS Backend mit AWS AppSync und vielen tollen weiteren AWS Services gebaut. Nun…]]></description><link>https://martinmueller.dev/wordpress-with-docker/</link><guid isPermaLink="false">https://martinmueller.dev/wordpress-with-docker/</guid><category><![CDATA[de]]></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 Leute!&lt;/p&gt;
&lt;p&gt;Für meinen neusten Kunden habe ich ein tolles AWS Backend mit AWS AppSync und vielen tollen weiteren AWS Services gebaut. Nun stehe ich aber vor der spannende Aufgabe die AppSync bzw. GraphQL API in einem Wordpress Frontend aufrufbar zu machen. Ich habe schon viel über Wordpress gehört aber noch nie damit gearbeitet.&lt;/p&gt;
&lt;p&gt;Auch wird dieses Wordpress auf &lt;a href=&quot;https://raidbox.de&quot;&gt;Raidbox.de&lt;/a&gt; gehostet was es etwas schwierig macht das Deployment direkt zu verwalten. Kommend aus der DevOps Welt will ich natürlich das Wordpress Deployment so angenehm und automatisiert wie möglich konfigurieren.&lt;/p&gt;
&lt;p&gt;Drei Anforderungen wollte ich dabei vom dem Wordpress Deployment erfüllt haben. Erstens soll Wordpress lokal mit minimalem Aufwand ausführbar sein. Zweitens soll das Wordpress mit GitHub versioniert sein. Und drittens soll ein Synchronisation zwischen dem lokalen Wordpress und dem auf Raidbox gehosteten Wordpress stattfinden.&lt;/p&gt;
&lt;h1&gt;Wordpress&lt;/h1&gt;
&lt;p&gt;Wordpress ist ein Content Management System (CMS). Es wurde entwickelt zum erstellen von Blogposts. Es hat sich aber stark weiterentwickelt und wird nicht mehr nur für Blogposts benutzt. Über sogenannte Plugins werden neue Feature zu Wordpress hinzugefügt. Solche Features können sein eine Bezahlfunktion. Wir selber verwenden &lt;a href=&quot;https://digimember.de&quot;&gt;Digimember&lt;/a&gt; zum Verwalten eines Abobezahlsystems.&lt;/p&gt;
&lt;h1&gt;Wordpress mit Docker&lt;/h1&gt;
&lt;p&gt;Zur Lösung meines ersten Problems, also Wordpress lokal zum Laufen zu bekommen, habe ich mich dafür entschlossen Docker zu benutzen. Zum Glück war ich nicht der erste der das versucht bzw. erfolgreich geschafft hat. Es gibt viele gute Anleitungen im Internet wie ein Wordpress Deployment mit Docker aufsetzen kann. Zur Orchestrierung der Docker Container verwende ich Docker Compose und hier ist der 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;Der erste Docker Container &lt;strong&gt;wordpress&lt;/strong&gt; ist natürlich für Wordpress. Mit dem volume wordpress_files persistiere ich die wordpress files.&lt;/p&gt;
&lt;p&gt;Danach kommt der &lt;strong&gt;db&lt;/strong&gt; Container welche eine MySQL Datenbank deployed. Wordpress verwendet MySQL als Datenbank zum Speichern von Informationen wie Blogposts, Sites, User, Pluginconfigs und noch vielen mehr. Das Volume db persistiert dabei die Datenbank. Die nächsten zwei Volumes speichern SQL Scripte im Container unter /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;Dadurch werden die SQL Scripte beim ersten Start ausgeführt. Das erste Script wordpress.sql beinhaltet die kompletten Wordpress MySQL Datenbank welche vorher als Dump exportiert wurde. Das zweite Script macht ein Text Replacing von der Domaine zu 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;Das ist nötig weil ich das Deployment ja lokal zum Laufen bekommen möchte.&lt;/p&gt;
&lt;p&gt;Der letzt Container phpmyadmin ist eine graphische Verwaltung für die MySQL DB.&lt;/p&gt;
&lt;h1&gt;GitHub&lt;/h1&gt;
&lt;p&gt;Den Code also die Wordpress Files und das Docker Compose File nun zu einem GitHub Repository zu pushen ist ein leichtes. Dafür muss ja einfach nur ein neues GitHub Repository erstellt werden und die Dateien in dieses kopiert und gepusht werden.&lt;/p&gt;
&lt;h1&gt;Nach Raidbox.de syncen&lt;/h1&gt;
&lt;p&gt;Wie Eingangs schon erwähnt, Raidbox.de ist unserer Hoster für Wordpress. Um nun die MySQL Datenbank und die Wordpress files dort zu aktualsieren habe ich mich für rsync in Kombination mit ssh entschieden. Dafür habe ich einen Workflow entwickelt:&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 than 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;Dieser Sync Workflow wird eventuell noch geändert in Zukunft und die Anzahl der Schritte reduziert. So wie dieser jetzt gestaltet ist, lassen sich immer noch über den normalen, über Raidbox erreichbaren Wordpress Editor, z.B. Blogs hinzufügen. Diese neuen Blogposts gehen dann beim nächsten Sync Workflow nicht verloren. Nachfolgend zeige ich noch die verwendeten 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=geheim 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;Hier sieht man wie mittels rsync, ssh und einem private key (~/ssh/example) die wordpress files zuerst gepusht und dann gepullt werden. Zusätzlich wird noch die MySQL DB auf Raidbox gedumpt und mitgepullt&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;geheim 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;Dieses Script such nach dem MySQL Docker Container und erstellt einen DB dump. Anschließend werden die urls wieder zu den originalen url Namen umgeschrieben. Dieser Dump kann nun mit dem Wordpress auf Raidbox importiert werden. Üblicherweise passiert das mit PHP Admin in Raidbox.&lt;/p&gt;
&lt;h1&gt;HTML als Code&lt;/h1&gt;
&lt;p&gt;Eine Sache die mich bei Wordpress sehr stört ist der Inline Editor für HTML und JavaScript Code. Im Vergleich zu z.B. Visual Studio Code bietet dieser null Funktionalität. Was ich als gerne hätte ist, dass die HTML und JavaScript Codeabschnitte im Wordpress über lokale Files gemacht werden kann.&lt;/p&gt;
&lt;p&gt;Diese lokalen Files kann ich dann wie gewohnt mit meinem VS Code Editor bearbeiten und bekomme tolle Hilfestellungen wir Syntaxkorrektur, Syntaxhighlighting und viele mehr. Das habe ich erreicht indem ich das HTML und JavaScript in iFrames, welche auf die Files pointen:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;/wp-content/themes/Impreza/get-vms.html&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ein Problem hat das Ganze aber wahrscheinlich noch. Es ist nicht Skalierbar bzw. Responsive wenn sich die größe des Bildschirms ändert weil man z.B. die Wordpress Seite mit einem Handy besucht.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Wordpress ist eine interessante neue Erfahrung für mich. Ich mag den Wordpresseditor welcher ein graphisches Bauen der Webside ermöglicht. Allerdings habe ich viele out of the box DevOps Techniken vermisst. Macht aber nix mit den hier beschriebenen Ansätzen macht die Entwicklung mit Wordpress wesentlich mehr Spaß.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 mit Lambda]]></title><description><![CDATA[Hi Leute! Ich arbeite zurzeit an einem spannenden Projekt bei dem es möglich sein soll flexibel über eine API, Ec2 Instanzen zu erstellen…]]></description><link>https://martinmueller.dev/aws-deploy-cfn-with-lambda/</link><guid isPermaLink="false">https://martinmueller.dev/aws-deploy-cfn-with-lambda/</guid><category><![CDATA[de]]></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 Leute!&lt;/p&gt;
&lt;p&gt;Ich arbeite zurzeit an einem spannenden Projekt bei dem es möglich sein soll flexibel über eine API, Ec2 Instanzen zu erstellen. Diese Instanzen sollen dann dem Kunden zu Übungszwecken zur Verfügung gestellt werden. Die Instanzen sollen dabei für den Kunden angepasst werden, also ein bestimmtes Setting haben wie dem Ec2 Typen, ein paar spezielle Tags und einiges mehr.&lt;/p&gt;
&lt;p&gt;Das Deployment der Ec2 Instanzen soll möglichst kostengünstig durch Lambdas geschehen. Vor ca einem Jahr hatte ich schonmal ein ähnliches Projekt gemacht bei dem dynamisch Ec2 Instanzen für ein Alfresco Deployment erzeugt werden. &lt;a href=&quot;https://martinmueller.dev/alf-provisioner-eng&quot;&gt;Alfresco Provisioner&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wie sich möglichst dynamisch und auch extrem einfach wartbar die Ec2 Instanzen mit AWS CDK über eine API wie Api Gateway oder Appsync deployen lassen, erkläre ich in den nächsten Abschnitten.&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; ist ein Open Source Framework zu Erstellung und Verwaltung von AWS Ressourcen. Durch die Verwendung von dem Entwickler vertrauten Sprachen wie TypeScript oder Python wird die Infrastructure as Code beschrieben. Dabei synthetisiert CDK den Code zu AWS Cloudformation Templates und kann diese optional gleich deployen.&lt;/p&gt;
&lt;p&gt;AWS CDK erfährt seit 2019 ein stetigen Zuwachs von begeisterten Entwicklern und hat bereits eine starke und hilfsbereite Community die z.B. sehr auf &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt; aktiv ist. Es gibt natürlich noch viel mehr zu sagen über AWS CDK und ich empfehle euch es zu erforschen. Schreibt mir, wenn ihr Fragen habt.&lt;/p&gt;
&lt;p&gt;Im nächsten Abschnitt fasse ich kurz die Anforderungen für das dynamische Ec2 Deploying über eine API zusammen.&lt;/p&gt;
&lt;h1&gt;Anforderungen&lt;/h1&gt;
&lt;p&gt;Die Ec2 Instanzen sollen dynamisch über eine API wie AWS ApiGateway, welches ein REST API implementiert oder AWS AppSync, welches ein GraphQL implementiert, deploybar sein. Dabei sollen gewisse Tags wie UserId oder VmType an die Ec2 Instanz geheftet werden. Damit lassen sich die Ec2 Instanzen dann wieder leicht auffinden und z.B. in einem React Frontend anzeigen.&lt;/p&gt;
&lt;p&gt;Für die Verwaltung, also Erstellung, Löschung und Update der zur Ec2 Instanz gehörenden Resourcen, soll mit Cloudformation (kurz: CFN) geschehen. Cloudformation ist ein praktischer AWS Service zur Verwaltung von solchen Resourcen. Somit kann der Ec2 Stack einfach erstellt, angepasst oder gelöscht werden. Ein weiterer Vorteil für die Verwendung von CFN ist, dass sich so dieser Teil auch separat von Rest wie der API testen lässt. Ich habe dafür sogar eine eigene Staging Pipeline erstellt &lt;a href=&quot;https://martinmueller.dev/cdk-pipeline-lib&quot;&gt;Stating Lib&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Für die Erstellung der CFN Templates möchte ich AWS CDK verwenden, da die Verwendung von CDK die Erstellung und Wartung des Ec2 Stacks extrem erleichtert.&lt;/p&gt;
&lt;p&gt;Das von CDK synthetisierte Ec2 CFN Template soll durch eine Lambda deployed werden.&lt;/p&gt;
&lt;h1&gt;Problem&lt;/h1&gt;
&lt;p&gt;Leider ist AWS CDK alleine nicht für diesen Use Case geschaffen. Das Hauptproblem ist, dass die CFN Parameter nicht flexibel sein können und nach der Synth Phase die Parameter festgeschrieben wurden. Dieser Nachteil könnte umgangen werden indem man immer einen kompletten deploy mit Context Parametern z.B.&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;macht. Das ist aber sehr unpraktisch da es sehr viel Build time beansprucht und jedes mal ein neues CFN Template quasi erzeugt wird.&lt;/p&gt;
&lt;p&gt;Um dieses Problem zu lösen habe ich mich entschieden Cloudformation direkt zu benutzen. Denn CFN hat das schöne Feature der Parameter. Bei jedem CFN Deployment können also Parameter spezifiziert werden um z.B. den Namen der Ec2 Instanz anzupassen. Genau das wonach ich gesucht habe.&lt;/p&gt;
&lt;h1&gt;Lösung&lt;/h1&gt;
&lt;p&gt;Ich verwende also CDK für den Ec2 Stack und dem Lambda welches den Ec2 Stack dynamisch deployen soll. Fangen wir mal mit dem Lambda an:&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;Ich verwende hier die &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/aws-lambda-nodejs-readme.html&quot;&gt;LambdaJS&lt;/a&gt; Variante. Diese hat den Vorteil dass ich die Lambda &lt;strong&gt;scheduler.ts&lt;/strong&gt; direct in TypeScript definieren kann und das Construct selbstständig diese in JS convertiert und in AWS hochlädt. Das ist als ein toller Grad von Abstraktion. Und mit dem afterBundling webhook kann ich das CFN Template schonmal in die Lambda hochladen. Somit muss ich nicht kompliziert mit einem anderen Storage wie S3 oder EFS arbeiten.&lt;/p&gt;
&lt;p&gt;Als nächstes schauen wir uns mal die &lt;strong&gt;scheduler.ts&lt;/strong&gt; an:&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;Dadurch dass ich ein DynamoDBStreamEvent als Input verwenden, verkompliziert es etwas den Code. Prinzipiell wichtig sind aber diese Zeilen:&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;Hier wird also das CFN Template aus der Datei ec2-vm-stack.template.json geladen und mittels AWS SDK &lt;strong&gt;createStack&lt;/strong&gt; applied.&lt;/p&gt;
&lt;p&gt;Bleibt also nur noch die ec2-vm-stack.template.json. Wie erzeuge ich diese? Well es ist wie bereits gesagt auch ein CDK Stack. Allerdings benutzt dieser CFN parameters als Input für &lt;strong&gt;userIdParam&lt;/strong&gt; und &lt;strong&gt;vmTypeParam&lt;/strong&gt;. Und hier ist der code für den 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;Interessant ist, dass ich die CFN Parameter &lt;strong&gt;userIdParam&lt;/strong&gt; und &lt;strong&gt;vmTypeParam&lt;/strong&gt; verwende für den dynamischen Anteil des Ec2 Stacks. Wird der Stack nun als über die Lambda erzeugt, bekommt z.B. die Ec2 Instanz die beiden Tags UserId und VmType mit den Werten der CFN Parameter.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Ec2 Instanzen mittels CFN und Lambdas zu erzeugen ist ne coole Sache. Mit CDK lässt sich alles also die Lambda, die API und der Ec2 Stack sehr leicht formulieren und erweitern. Super cool ist auch, dass es mit CFN sehr leicht ist andere Ressourcen in Zukunft mit dazuzuholen. So will ich z.B. in Zukunft eventuell auch einen S3 Bucket für das Deployment bereitstellen. Ich hoffe der Beitrag hat euch gefallen und vielleicht sogar geholfen. Habt ihr Fragen? Schreibt mir :) !&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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! Mit Custom Constructs ist es möglich gewisse Features als Level 2 AWS CDK Constructs zu implementieren. Tatsächlich sind viele…]]></description><link>https://martinmueller.dev/cdk-construct-checker/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-construct-checker/</guid><category><![CDATA[de]]></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;Mit Custom Constructs ist es möglich gewisse Features als Level 2 AWS CDK Constructs zu implementieren. Tatsächlich sind viele der bereits verwendeten AWS CDK Construct bereits Level 2 Constructs. Ich habe bereits einige Custom Constructs gebaut. Da wäre die &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-build-badge&quot;&gt;Build Badge&lt;/a&gt; und die &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;Wie wir alle wissen iteriert AWS CDK sehr schnell und es wird quasi wöchentlich eine neue Version released. Bei jedem Release besteht die Gefahr, dass meine Custom Constructs nicht mit der releasten CDK Version kompatibel ist. Von daher habe ich einen GitHub Workflow entwickelt der automatisch die Kompatibilität meiner Custom Constructs gegen die neue Version testet.&lt;/p&gt;
&lt;p&gt;In den nächsten Abschnitten möchte ich erklären wie der Kompatibilitätscheck funktioniert und wie ich ihn implementiert habe.&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; ist ein Open Source Framework zu Erstellung und Verwaltung von AWS Ressourcen. Durch die Verwendung von dem Entwickler vertrauten Sprachen wie TypeScript oder Python wird die Infrastructure as Code beschrieben. Dabei synthetisiert CDK den Code zu AWS Cloudformation Templates und kann diese optional gleich deployen.&lt;/p&gt;
&lt;p&gt;AWS CDK erfährt seit 2019 ein stetigen Zuwachs von begeisterten Entwicklern und hat bereits eine starke und hilfsbereite Community die z.B. sehr auf &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt; aktiv ist. Es gibt natürlich noch viel mehr zu sagen über AWS CDK und ich empfehle euch es zu erforschen. Schreibt mir, wenn ihr Fragen habt.&lt;/p&gt;
&lt;p&gt;Im nächsten Abschnitt erkläre ich wie de Kompatibilitätscheck mit der AWS CDK Version funktioniert.&lt;/p&gt;
&lt;h1&gt;Kompatibilitätscheck&lt;/h1&gt;
&lt;p&gt;Einmal am Tag curlt ein GitHub Workflow, hier Versionschecker genannt, auf die Seite &lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;https://github.com/aws/aws-cdk&lt;/a&gt; und extrahiert die letzte releaste CDK Version. Dann erstellt der Versionchecker einen Branch im Namenpattern bump/1.X.X . Als also kürzlichst die Version 1.103.0 releast wurde, erstellte der Versionschecker den Branch bump/1.103.0 . Dann erstellt der Versionchecker einen Pull Request gegen master. Der Pull Request beinhaltet nun die neue CDK Version. Das wird erreicht in dem der Versionschecker ein string Replace macht in der .projenrc.js File. Zum Beispiel wird:&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;ersetzt durch&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;Nun wird ein normaler Build aber mit neuer CDK Version durchgeführt. Der Build testet zu einem die Kompatibilität der CDK Interfaces bzw. dependencies und zum anderen werden die unit Tests automatisiert durchgeführt. Die Verwendung des Versionschecker bedingt also eine gute Unit Testingstrategie. Daher können getestet werden Lambda Code z.B.:&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;und die zu erwarteten synthetisierten Cloudformation Templates:&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;Diese Beispiele wurden aus meinem &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-build-badge&quot;&gt;Build Badge&lt;/a&gt; Construct kopiert.&lt;/p&gt;
&lt;h1&gt;Versionschecker - GitHub Workflow&lt;/h1&gt;
&lt;p&gt;Der Versionschecker ist ein GitHub Workflow und wird täglich um 4 Uhr ausgeführt.&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;Der curl für die Versionsnummer akzeptiert nur v1.X Tags. v2.X ist per Design nicht kompatibel mit meinen CDK Stacks. Der PR würde also immer fehlschlagen.&lt;/p&gt;
&lt;p&gt;Es wäre auch möglich manuel gegen bestimmte Versionen zu testen. Dafür müssen einige Zeilen Code auskommentierten bzw. einkommentiert werden. Z.B. Zum manuellen Triggern muss der push master einkommentiert werden. Aucht muss die Action zum curlen der CDK Version auskommentiert und die darüber liegende CDK Version Action einkommentiert werden.&lt;/p&gt;
&lt;h1&gt;Getestete Versions Liste&lt;/h1&gt;
&lt;p&gt;Mir kam dan noch die coole Idee zur Erstellung einer List von den bereits getesteten CDK Versionen. Es werden einfach die erstellten Pull Requests mit dem zuvor erstellten Label &lt;strong&gt;cdk-version-test&lt;/strong&gt; versehen.&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;Dann kann einfach per Link auf einen Filter mit dem Label verwiesen werden wie z.B. &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; . Und tada es werden alle PRs zum Versionstest angezeigt.&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;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;AWS CDK ist nachwievor das optimale Framework für Infrastructure as Code in AWS. Mit meinen Custom Constructs hoffe ich der Community zurückzugeben. Um nun auch immer die beste Experience zu gewährleisten, habe ich einen Workflow entwickelt, der die CDK Versionskompatibilität überprüft. Den Workflow zu erstellen hat mir riesen Spaß gemacht. Noch toller ist jetzt aber eine PR Liste zu haben wo ich genau sehen kann ob die Versionschecks geklappt haben. Ich habe noch weitere spannende CDK Themen in meinem 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;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 und DataSource CDK Custom Constructs]]></title><description><![CDATA[Hi. In meinen vorherigen Blogposts habe ich bereits viel beschrieben und gezeigt wie man mit Hilfe von AWS QuickSight Analysen aus DynamoDB…]]></description><link>https://martinmueller.dev/qs-constructs/</link><guid isPermaLink="false">https://martinmueller.dev/qs-constructs/</guid><category><![CDATA[de]]></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 meinen vorherigen Blogposts habe ich bereits viel beschrieben und gezeigt wie man mit Hilfe von AWS QuickSight Analysen aus DynamoDB Tabelle generieren kann. Unglücklicherweise ist QuickSight nur minimal unterstützt von Cloudformation und QuickSight&apos;s DataSource und DataSet sind bisher nur auf der Roadmap &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;Deshalb habe ich AWS CDK Custom Constructs für &lt;a href=&quot;https://github.com/mmuller88/cdk-quicksight-constructs&quot;&gt;DataSource und DataSet&lt;/a&gt; entwickelt. In diesem Post gehe ich etwas genauer darauf ein was QuickSight DataSources und DataSets sind und wie ich mittels AWS CDK Custom Construct deploybar mache.&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; ist ein Open Source Framework zu Erstellung und Verwaltung von AWS Ressourcen. Durch die Verwendung von dem Entwickler vertrauten Sprachen wie TypeScript oder Python wird die Infrastructure as Code beschrieben. Dabei synthetisiert CDK den Code zu AWS Cloudformation Templates und kann diese optional gleich deployen.&lt;/p&gt;
&lt;p&gt;AWS CDK erfährt seit 2019 ein stetigen Zuwachs von begeisterten Entwicklern und hat bereits eine starke und hilfsbereite Community die z.B. sehr auf &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt; aktiv ist. Es gibt natürlich noch viel mehr zu sagen über AWS CDK und ich empfehle euch es zu erforschen. Schreibt mir, wenn ihr Fragen habt.&lt;/p&gt;
&lt;h1&gt;DataSource&lt;/h1&gt;
&lt;p&gt;Eine QuickSight DataSource definiert die Herkunft der Daten für die Analyse. Welche Datenquellen dabei möglich sind, seht ihr sehr gut in der &lt;a href=&quot;https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/QuickSight.html#createDataSource-property&quot;&gt;SDK Dokumentation&lt;/a&gt;. Das DataSource Construct benutzt dabei auch die SDK Parameterdefinition als typed Input.&lt;/p&gt;
&lt;p&gt;Das konkrete Interface findet ihr &lt;a href=&quot;https://github.com/mmuller88/cdk-quicksight-constructs/blob/main/src/datasource.ts&quot;&gt;hier&lt;/a&gt;. Wenn man zum Beispiel Athena als DataSource definieren möchte sieht das so aus:&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; ist der &lt;a href=&quot;https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/QuickSight.html#createDataSource-property&quot;&gt;getypte Parameter vom SDK&lt;/a&gt;. Ich finde es ziemlich cool das wir hier nun Typesupport haben und so auch sehr einfach andere Quellen als DataSource wie Aurora oder RDS definieren können &amp;#x3C;3 . Die &lt;strong&gt;workGroup&lt;/strong&gt; im Beispiel muss vorher erstellt sein. Das kann man manuell mit der AWS Console in Athena machen oder noch besser mit Athena. Wie genau das geht, habe ich bereits in einem vorherigen &lt;a href=&quot;https://martinmueller.dev/cdk-ddb-quicksight&quot;&gt;Blogpost&lt;/a&gt; erklärt.&lt;/p&gt;
&lt;h1&gt;DataSet&lt;/h1&gt;
&lt;p&gt;Eine DataSet kann dann verwendet werden um die DataSources zu verfeinern und zu konkretisieren. Dabei können zum Beispiel joins oder transforms definiert werden. Alle Möglichkeiten sehr ihr auch hier in der &lt;a href=&quot;https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/QuickSight.html#createDataSet-property&quot;&gt;DataSet SDK Dokumentation&lt;/a&gt;. Sehr wichtig zu wissen, es müssen die Permissions für DataSource und DataSet immer richtig gesetzt werden. Das habe ich zum Beispiel in den Constructs schon eingebaut.&lt;/p&gt;
&lt;p&gt;Die Implementierung des DataSets ist &lt;a href=&quot;https://github.com/mmuller88/cdk-quicksight-constructs/blob/main/src/dataset.ts&quot;&gt;hier&lt;/a&gt;. Nachfolgend schildere ich ein etwas komplexeres Beispiel bei dem logische Tabellen aus der DataSource gejoint werden.&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 diesem Beispiel werden virtuell erst die zwei Tabellen &lt;strong&gt;users&lt;/strong&gt; und &lt;strong&gt;practices&lt;/strong&gt; erzeugt und anschließend miteinander gejoined um herauszufinden zu welcher practice der user zugeordnet ist.&lt;/p&gt;
&lt;p&gt;Auch führe ich hier ein Daten Transformation durch. Ich möchte gerne das &lt;strong&gt;age&lt;/strong&gt; der user wissen, allerdings ist in den Daten nur das Geburtsdatum vermerkt. Also führe ich eine Tranformation durch bei der das Alter berechnet wird und als neue Spalte mit Namen &lt;strong&gt;age&lt;/strong&gt; definiert wird.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;QuickSight ist ein cooles AWS Tool zum Visualisieren von Data Insights. Da ich ein riesen Fan von Infrastructure as Code bin will ich alle QuickSight Ressourcen in CDK haben. Leider sind die DataSource und DataSet noch nicht von Cloudformation unterstützt. Solange das noch so ist, werde ich und könnt ihr gerne meine CDK Custom Construct als Ersatz verwenden :).&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 Analysen mit QuickSight und AWS CDK - Zu große Tabellen]]></title><description><![CDATA[Hi. In meinem letzten Blogpost habe ich über spannende Arbeiten mit AWS Athena und AWS QuickSight berichtet. Wenn ihr Analysen von kleinen…]]></description><link>https://martinmueller.dev/cdk-ddb-quicksight-2/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-ddb-quicksight-2/</guid><category><![CDATA[de]]></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 meinem &lt;a href=&quot;https://martinmueller.dev/cdk-ddb-quicksight&quot;&gt;letzten Blogpost&lt;/a&gt; habe ich über spannende Arbeiten mit AWS Athena und AWS QuickSight berichtet. Wenn ihr Analysen von kleinen AWS DynamoDB Tabellen machen wollt, sollte alles reibungslos funktionieren. Mit klein meine ich eine relativ geringe Anzahl von Spalten in der Tabelle.&lt;/p&gt;
&lt;p&gt;Mir passierte es nämlich das bei der Verarbeitung der &lt;a href=&quot;https://www.take2.co/&quot;&gt;TAKE2&lt;/a&gt; Daten, die benötigte Spalten für QuickSight garnicht angezeigt wurden. Nun ist die Anzahl der Spalten in den TAKE2 Daten mit mehr als 700 alles andere als klein! Wie ich das Problem gelöst habe und sogar mit AWS CDK in Code gießen konnte, erfahrt ihr in den nächsten Abschnitten.&lt;/p&gt;
&lt;p&gt;Zuvor möchte ich auch dieses mal den Sponsor &lt;a href=&quot;https://www.take2.co/&quot;&gt;TAKE2&lt;/a&gt; für diesen Blogpost danken.&lt;/p&gt;
&lt;h1&gt;Lösung&lt;/h1&gt;
&lt;p&gt;Also nochmal kurz zusammengefasst. Die DynamoDB Tabelle ist viel zu groß und der Lambda &lt;a href=&quot;https://github.com/awslabs/aws-athena-query-federation/blob/master/athena-dynamodb&quot;&gt;AthenaDynamoDBConnector&lt;/a&gt; ist nicht mehr vernünftig in der Lage alle Spalten zu erkennen. Zum Glück haben die Programmierer des Connectors diesen Fall mitbedacht und eine Möglichkeit eingebaut, gezielt Spalten mit deren Namen und Typen definieren zu können.&lt;/p&gt;
&lt;p&gt;Die genauen Anweisungen stehen auch im &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;. Kurz gesagt muss eine AWS Glue Table erstellt werden. Der Connector kann dann anhand der dort definierten Spalten die gewünschten Spalten erkennen.&lt;/p&gt;
&lt;p&gt;Um es anhand des auch im letzten Post verwendeten AWS Komponentendiagrams zu visualisieren, muss lediglich die Glue Tabelle hinzugefügt werden:&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;Ich abe die CDK Glue Table Erweiterung in ihren eigenen &lt;a href=&quot;https://github.com/mmuller88/ddb-quicksight/blob/main/src/glue-stack.ts&quot;&gt;CDK Stack&lt;/a&gt; gepackt. Hier ist der 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 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;Die zu mappenen DynamoDB Spalten müssen einfach als columns in der Glue Table definiert werden. Hier aufgepasst! Glue Table unterstützt bestimmte Zeichen nicht wie Capslock und andere Sonderzeichen. Deswegen muss eventuell noch ein columnMapping vorgenommen werden!&lt;/p&gt;
&lt;p&gt;Nach dem deployen können die in &lt;strong&gt;columns&lt;/strong&gt; definierten Spalten in Athena und QuickSight verwendet werden.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Das Analysieren von großen DynamoDB Tabellen ist nicht ganz so einfach. Mit der Verwendung von AWS Glue Tables kann der Lambda AthenaDynamoDBConnector aber trotzdem zuverlässig die gewünschten Spalten erkennen.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 Analysen mit QuickSight und AWS CDK]]></title><description><![CDATA[Hi. AWS DynamoDB ist eine extrem performante und skalierbare NoSQL Datenbank. Durch das fehlen eines Schemas können Daten, in DynamoDb Items…]]></description><link>https://martinmueller.dev/cdk-ddb-quicksight/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-ddb-quicksight/</guid><category><![CDATA[de]]></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><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;AWS DynamoDB ist eine extrem performante und skalierbare NoSQL Datenbank. Durch das fehlen eines Schemas können Daten, in DynamoDb Items genannt, extrem flexibel sein. Das erlaubt auch eine Art evolutionäre Weiterentwicklung der Items indem einfach neue Spalten angelegt werden können.&lt;/p&gt;
&lt;p&gt;Das ganze hat aber einen Haken. Dadurch, dass wir uns nicht mehr in der Welt der relationalen Daten befinden, können wir keine relationalen Operationen mehr ausführen wie zum Beispiel Joins oder die üblichen relationalen Operationen wie COUNT, ORDER BY, GROUP by und viele mehr. Nun fragst du dich warum sollte ich zum Beispiel Joins ausführen können, die haben uns doch schon genervt bei den relationalen Datenbanken? Wir können Joins zum Beispiel bei Analysen gebrauchen. Ich versuche das zu erklären anhand eines Shops:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Top X verkauften Produkte im Zeitraum von t1 bis t2 grouped by Geschlecht&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In unserem Beispiel befinden sich die User und die verkauften Produkte jeweils in ihrer eigenen DynamoDB Tabelle und sind indirekt über eine userId verbunden. Denkbar wäre aber auch dass sich beide in der gleichen Tabelle, aber in unterschiedlichen Datensätzen bzw. Rows befinden. DynamoDB erlaubt keine Joins und somit können wir keine Beziehung zwischen verkauften Produkten und dem Geschlecht herstellen.&lt;/p&gt;
&lt;p&gt;Die Lösung für das Problem ist AWS Athena, QuickSight, Lambda und S3. Mit einer Lambda werden die DynamoDB Items als flache JSON File in ein S3 gespeichert. Dann lassen wir Athena darauf zugreifen. QuickSight benutzt Athena dann als Datenengine um Joins, Analysen und Dashboards zu erstellen. Wie ihr das mit AWS CDK automatisiert und eine Beschreibung der verwendeten AWS Services folgen in den nächsten Abschnitten. Für die Ungeduldigen hier schonmal der &lt;a href=&quot;https://github.com/mmuller88/ddb-quicksight&quot;&gt;Code&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Zuvor möchte ich aber noch den Sponsor für diesen Blogpost und dem aufregenden Projekt um Analysen von DynamoDB Tabellen mittels QuickSight durchzuführen. Vielen Dank an &lt;a href=&quot;https://www.take2.co/&quot;&gt;TAKE2&lt;/a&gt; dass ich in eurem agilen und motiviertem Team sein darf um so aufregende AWS CDK Aufgaben wie diese arbeiten zu können.&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; ist eine gemanagte NoSQL Datenbank mit sehr guter Performance und Skalierung. Durch das managen der Datenbank von AWS entfällen aufwendige Administrative Aufgaben wie Installation oder Wartung. DynamoDB besitzt auch Backup Features wie on demand oder Point-in-Time Recovery.&lt;/p&gt;
&lt;p&gt;In DynamoDB müssen die eingefügten Daten keinem festdefiniertem Schema folgen wie in etwa bei relationen Datenbanken. Das ist super flexibel und sehr nützlich, kann aber auch zu Problemen führen wie Unübersichtlichkeit oder Inkonsistenzen bei den Spaltennamen. Von daher empfehle ich nur bestimmte Spalten in der Tabelle zuzulassen. Das kann z.B. erreicht werden durch eine Schemavalidierung im Api Gateway oder der Verwendung eines GraphQL Schema in AWS AppSync.&lt;/p&gt;
&lt;h1&gt;AWS Athena&lt;/h1&gt;
&lt;p&gt;AWS Athena erlaubt das Querien von Daten. Zum Zugriff auf die Daten benutzt der Entwickler Standard-SQL als Query Language. Als Datenquelle können verschiedene AWS Services dienen wie S3, RedShift und seit neuestem auch DynamoDB. Der Vorteil an Athena ist, dass es Serverless ist und man sich somit direkt auf die Datenabfrage konzentrieren kann.&lt;/p&gt;
&lt;p&gt;Um DynamoDB als Datenquelle für Athena zu setzen braucht man einen Lambda Connector. Der Connector schreibt dabei alle Items aus der Tabelle in einen S3 Bucket. Zum Glück bietet AWS eine SAM Lambda bereits an die den Job übernimmt. Diese Lambda heißt &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 ist ein Service zum Erstellen und Analysieren von Visualisierungen der Kundendaten. Die Kundendaten können dabei in AWS Services liegen wie S3, RedShift oder wie in unserem Fall 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 kann zum jetzigen Zeitpunkt noch nicht direkt Daten von DynamoDB einlesen und es muss ein kleiner Zwischenschritt gemacht werden. Die DynamoDB Daten müssen in einem S3 Bucket z.B. als JSON exportiert werden. Dann kann QuickSight die sich im S3 befindenden Daten einlesen.&lt;/p&gt;
&lt;p&gt;Um die Daten in den S3 Bucket zu schieben eignet sich der Ansatz eine AthenaDynamoDBConnector Lambda zu verwenden. Näheres darüber findest du im nächsten Abschnitt.&lt;/p&gt;
&lt;p&gt;Quicksight bietet viele coole Funktionen zum Verarbeiten und Visualisieren von Daten die zum Beispiel aus DynamoDB kommen können. Auch lassen sich diese mit CDK als Code definieren.&lt;/p&gt;
&lt;p&gt;Ich arbeite daran die erstellen QuickSight Analysen via CDK in Templates zu speichern um sie so cross account mäßig zugreifbar zu machen. Das ermöglicht dann Analysen auf einem dev account zu Erstellen und Testen und diese dann in den prod Account automatisiert zu via CDK zu deployn. Wie genau das alles von statten gehen soll erkläre im nächsten Blogpost.&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; ist ein Open Source Framework zu Erstellung und Verwaltung von AWS Ressourcen. Durch die Verwendung von dem Entwickler vertrauten Sprachen wie TypeScript oder Python wird die Infrastructure as Code beschrieben. Dabei synthetisiert CDK den Code zu AWS Cloudformation Templates und kann diese optional gleich deployen.&lt;/p&gt;
&lt;p&gt;AWS CDK erfährt seit 2019 ein stetigen Zuwachs von begeisterten Entwicklern und hat bereits eine starke und hilfsbereite Community die z.B. sehr auf &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt; aktiv ist. Es gibt natürlich noch viel mehr zu sagen über AWS CDK und ich empfehle euch es zu erforschen. Schreibt mir, wenn ihr Fragen habt.&lt;/p&gt;
&lt;p&gt;Mit AWS CDK habe ich einen hohen Automatisierungsgrad bei der Erstellung und Verwaltung des DynamoDB QuickSight Deployments erreicht. Dabei werden die benötigten AWS Ressourcen und dessen Konfigurationen schön als Code definiert und dann einfach ausgeführt. Und hier seht ihr ein Komponentendiagram:&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;Den AWS CDK Code für das DynamoDB Athena Deployment findet ihr in meinem &lt;a href=&quot;https://github.com/mmuller88/ddb-quicksight/blob/main/src/ddb-athena-stack.ts&quot;&gt;Repo&lt;/a&gt;. Unbedingt dort auch die Readme ansehen da diese viele wichtige Anweisungen und Informationen enthält. Leider konnte ich nicht alles in AWS CDK verfassen da z.B. die SAM Lambda AthenaDynamoDBConnector lässt sich nicht oder nur schwierig in AWS CDK übersetzen und sie muss bis jetzt noch manuel deployed werden.&lt;/p&gt;
&lt;h1&gt;Ausblick&lt;/h1&gt;
&lt;p&gt;Es wäre super cool wenn der AthenaDynamoDBConnector auch in AWS CDK erhältlich wäre. Auch scheinen mir die QuickSight Cloudformation Ressourcen noch sehr unausgereift da manches noch garnicht unterstütz wird wie z.B. das DataSet. Ein &lt;a href=&quot;https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/274&quot;&gt;GitHub Issue&lt;/a&gt; wurde bereits schon erstellt.&lt;/p&gt;
&lt;p&gt;Wie schon in der QuickSight Sektion erwähnt, arbeite ich daran die Analysen von QuickSight mittel CDK zu persistieren und dann Cross Account mäßig verfügbar zu machen. Meine Findings werde ich dann im nächsten Blogpost zeigen.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;AWS QuickSight ist ein spannendes Analysetool zum Auswerten von Daten in einer DynamoDB Tabelle. Daten sind ja das neue Gold und von daher ist es extrem wichtig Daten aus einer DynamoDB Tabelle verarbeiten zu können. Wenn dabei noch vertraute mechanismen wie SQL Queries, Aggregat Funktionen benutzt werden können ist das super. Auch bietet QuickSight coole graphische Lösungen zum Anzeigen von Analysen und Dashboards. Ich bin schon sehr darauf gespannt mehr damit zu arbeiten.&lt;/p&gt;
&lt;p&gt;Vielen Dank auch an Jared Donboch für den extrem hilfreichen 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; . Basierend darauf konnte ich so viel wie möglich automatisieren indem ich es in einen AWS CDK Stack verfasst habe.&lt;/p&gt;
&lt;p&gt;Nochmal vielen Dank an &lt;a href=&quot;https://www.take2.co/&quot;&gt;TAKE2&lt;/a&gt; für das Sponsoring dieses Blogposts.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Ein sehr coole DevOps AWS CDK Todolist]]></title><description><![CDATA[Hi. Schon lange träume ich von dem Bau einer Platform mit einer tollen DevOps Experience. Ich möchte so coole sachen darin haben wie…]]></description><link>https://martinmueller.dev/cdk-appsync/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-appsync/</guid><category><![CDATA[de]]></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;Schon lange träume ich von dem Bau einer Platform mit einer tollen DevOps Experience. Ich möchte so coole sachen darin haben wie:&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;Ein Staging z.B. dev, qa, prod&lt;/li&gt;
&lt;li&gt;automatisierte Tests&lt;/li&gt;
&lt;li&gt;das alles mit so wenig TypeScript Code wie nötig&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ich habe das nun gefunden mit der Verwendung der folgenden Technologien. AWS CDK zum managen der Infrastructure as Code. AWS AppSync als Implementierung von GraphQL, AWS Amplify für die Frontend Website und das managen von Usern. Weiterhin AWS CodePipeline erweitert mit meiner 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;Anhand meins Todolisten Deployments will ich euch zeigen wie viel Power in meinem Deployment steckt. Aber zunächst werde ich erklären was AWS CDK ist.&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; ist ein Open Source Framework zu Erstellung und Verwaltung von AWS Ressourcen. Durch die Verwendung von dem Entwickler vertrauten Sprachen wie TypeScript oder Python wird die Infrastructure as Code beschrieben. Dabei synthetisiert CDK den Code zu AWS Cloudformation Templates und kann diese optional gleich deployen.&lt;/p&gt;
&lt;p&gt;AWS CDK erfährt seit 2019 ein stetigen Zuwachs von begeisterten Entwicklern und hat bereits eine starke und hilfsbereite Community die z.B. sehr auf &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt; aktiv ist. Es gibt natürlich noch viel mehr zu sagen über AWS CDK und ich empfehle euch es zu erforschen. Schreibt mir, wenn ihr Fragen habt.&lt;/p&gt;
&lt;h1&gt;Backend AWS AppSync, AWS DynamoDB and AWS Cognito&lt;/h1&gt;
&lt;p&gt;Der Code für das Backend ist 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 ist eine GraphQL Api Implementierung. GraphQL ist eine interessante neue API Technologie. Da GraphQL noch neu für mich ist, wage ich keine großen Aussagen jetzt und hier. Was mir aber sehr gut gefällt ist, dass sich die Anbindung an Datenbanken wie AWS DynamoDB sehr nativ anfühlt. Mich haben schon immer die nötigen Lambda Implementierungen bei AWS Api Gateway und das Anlegen neuer Endpoints genervt. Das alles scheint nicht mehr nötig mit der Verwendung von AWS AppSync.&lt;/p&gt;
&lt;p&gt;Für das Speichern von Items in der Todoliste verwende ich DynamoDB. Jedes Item bekommt dabei seine eigene ID, welche von dem AppSync Resolver zugewiesen wird. Darüber hinaus besitzt jedes Item einen Body und einen Username.&lt;/p&gt;
&lt;p&gt;AWS Cognito ist ein Service für die Userverwaltung und Userauthentifikation über Oauth. Dieser Service macht es sehr einfach einen professionellen und skalierbaren Identity Service mit allem drum und dran zu implementieren.&lt;/p&gt;
&lt;p&gt;Eine Deployment Pipeline deployed all diese Ressourcen in AWS Accounts. Die AWS Ressourcen für das Backend und die Deployment Pipeline selbst, werden mit AWS CDK als Infrastructure as Code bereitgestellt.&lt;/p&gt;
&lt;h1&gt;Frontend React, AWS Amplify, S3 Static Website&lt;/h1&gt;
&lt;p&gt;Der Code für das Frontend ist 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;Der Frontend Stack besteht aus einem React Build mit AWS Amplify UI Erweiterungen wie @aws-amplify/auth @aws-amplify/ui-components @aws-amplify/ui-react. Diese Erweiterungen helfen massiv bei der Userverwaltung. So ist es z.B. einfach möglich über den Loginscreen neue Benutzer anzulegen oder das Passwort zu ändern, falls man es vergessen haben sollte.&lt;/p&gt;
&lt;p&gt;Der React Build wird per Deployment Pipeline (siehe nächsten Abschnitt) in einen S3 Bucket kopiert. Der S3 Bucket ist als Static Website konfiguriert. Alle benötigten AWS Ressourcen für den S3 Bucket und der Deployment Pipeline werden ebenfalls mit AWS CDK bereitgestellt.&lt;/p&gt;
&lt;h1&gt;DevOps Pipelines&lt;/h1&gt;
&lt;p&gt;Jegliche Deployments heutzutage sollten eine vernünftige Deployment Pipeline besitzen die so coole Features hat wie automatisierte Builds, Deploys, Tests, Linting, Versioning und so weiter. Damit erreicht man einen ungleiblich gute Geschwindigkeit bei der Entwicklung und die Arbeit macht auch viel mehr Spaß weil lästige manuelle Tätigkeiten wie das Deployen zur Produktion oder manuelles Testen, fallen einfach weg.&lt;/p&gt;
&lt;p&gt;Mein Todolisten Deployment hat eine solche Deployment Pipeline. Jeweils das &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-todolist-ui&quot;&gt;Frontend&lt;/a&gt; und &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-todolist&quot;&gt;Backend&lt;/a&gt; besitzen ihre eigene Pipeline welche auf AWS CodePipeline und natürlich AWS CDK basiert. Für die Pipeline habe ich ein eigens AWS CDK Custom Construct entwickelt und auch schon darüber in einem vorherigen Post berichtet welchen ihr &lt;a href=&quot;https://martinmueller.dev/cdk-pipeline-lib&quot;&gt;hier&lt;/a&gt; sehen könnt.&lt;/p&gt;
&lt;h1&gt;Ausblick&lt;/h1&gt;
&lt;p&gt;Der &lt;a href=&quot;https://github.com/&quot;&gt;AppSync Transformer&lt;/a&gt; sieht sehr interessant aus. Mit ihm ist es möglich die &lt;a href=&quot;https://docs.amplify.aws/cli/graphql-transformer/overview&quot;&gt;AWS Amplify GraphQL Transformer&lt;/a&gt; einfacher zu nutzen. Somit können viele Zeilen Code gespart werden indem durch so coole labels wie @model @connection ein erweitertes GraphQL Schema generiert wird.&lt;/p&gt;
&lt;p&gt;Ich bin gerade auch dabei ein Udemy Kurs über das hier erwähnte Todolist Deployment zu verfassen. Falls ihr einen Gutschein dafür haben wollt, sagt mir bescheid und sobald es fertig ist, bekommt ihr einen.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;GraphQL is mega spannend. Ich glaube es ist eine zukunftsweisende API Technologie und ich kann es kaum abwarten mehr im professionellen Umfeld damit zu arbeiten.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 und GitHub]]></title><description><![CDATA[Hi. Unser Entwicklerteam hat ein spannendes Experiment ausprobiert. Wir arbeiten im Scrum und organisieren uns hauptsächlich mit GitHub. In…]]></description><link>https://martinmueller.dev/github-scrum/</link><guid isPermaLink="false">https://martinmueller.dev/github-scrum/</guid><category><![CDATA[de]]></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;Unser Entwicklerteam hat ein spannendes Experiment ausprobiert. Wir arbeiten im Scrum und organisieren uns hauptsächlich mit GitHub. In diesem Artikel beschreibe ich wie wir GitHub dafür benutzen.&lt;/p&gt;
&lt;p&gt;Auch wenn ich schon seit ungefähr 5 Jahren Erfahrung mit Scrum habe als Entwickler gebe ich hier einen kleinen Disclaimer. Ich habe nie eine Scrum Zertifizierung gemacht. Ich werde also wahrscheinlich Begriffe falsch wiedergeben oder einordnen. Ich würde dann gerne dich bitte mich zu korrigieren.&lt;/p&gt;
&lt;p&gt;Auch arbeitet unser Team erst seit gut einem Monat zusammen im Scrum. Das Team ist mit 4 Leuten 3 Fullstack Entwicklern und 1 Product Owner relativ klein. Trotzdem denke ich, dass dieser Beitrag euch dabei helfen kann euren Arbeitsprozess in eurem Team zu verbessern.&lt;/p&gt;
&lt;p&gt;Im nächsten Abschnitt erzähle ich mehr über GitHub und wie wir es nutzen um uns in Scrum zu organisieren.&lt;/p&gt;
&lt;h1&gt;GitHub und Scrum&lt;/h1&gt;
&lt;p&gt;Mein &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;GitHub Account&lt;/a&gt; is aktiv seit 2016. GitHub ist bei weitem meine liebste Git Provider Umgebung. Privat nutze ich GitHub sehr viel. Ich bin sehr froh, dass ich GitHub nun auch für die Arbeit verwenden kann. Unsere Hauptmotivation GitHub zur Organisation zu verwenden sind die geringen Kosten und die Tatsache, dass sich viele Entwickler bereits gut mit GitHub auskennen.&lt;/p&gt;
&lt;p&gt;Im nächsten Abschnitt erkläre ich wie wir einige GitHub Funktionen zur bewältigung unserer Scrum Arbeitsweise verwenden.&lt;/p&gt;
&lt;h2 id=&quot;github-issues-als-tickets&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#github-issues-als-tickets&quot; aria-label=&quot;github issues als 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 als Tickets&lt;/h2&gt;
&lt;p&gt;Die Issues bei GitHub lassen sich perfekt nutzen als Tickets für Scrum. Über Labels ist es sogar möglich den Tickets eine Size zu geben. Sizen meint in dem Kontext, dass eine Zahl für die Komplexität des Tickets von den Entwicklern vergeben wird. Üblicherweise sind das die Fibonacci Zahlen 1 3 5 8 13 .&lt;/p&gt;
&lt;p&gt;Auch können über Labels die Tickets ihrer jeweiligen Komponente zugewiesen werden. Komponente meint dabei eine Art Unterkategorie des Projektes wie z.B. &quot;component: api&quot; oder &quot;component: app&quot; .&lt;/p&gt;
&lt;h2 id=&quot;github-projects-als-scrum-boards&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#github-projects-als-scrum-boards&quot; aria-label=&quot;github projects als 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 als Scrum Boards&lt;/h2&gt;
&lt;p&gt;GitHub Projects eigenen sich hervorragend für die Scrum Boards. Wir haben 3 Projects für 3 Boards. Jedes Board repräsentiert dabei seinen eigenen Zeitbereich und Abstraktionsgrad.&lt;/p&gt;
&lt;h3 id=&quot;aktuelle-sprint-board&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aktuelle-sprint-board&quot; aria-label=&quot;aktuelle 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;Aktuelle Sprint Board&lt;/h3&gt;
&lt;p&gt;Das wichtigste Board ist dabei natürlich das &quot;Aktuelle Sprint Board&quot; (siehe mittig im Titelbild). Wir machen einen zweiwöchigen Sprint und mit dem &quot;Aktuelle Sprint Board&quot; reflektieren wir die Arbeit bzw. die Tickets an denen wir aktuelle arbeiten und arbeiten wollen. Es besitzt drei Spalten ToDo, In Progress und Done.&lt;/p&gt;
&lt;p&gt;Tickets aus dem Backlog Scrum Board, welches im nächsten Abschnitt vorgestellt wird, landen dann hier zuerst in der ToDo Spalte. Zu diesem Zeitpunkt sollten die Tickets verständlich und gesized sein. Am Ende jedes Sprints wird die Done Spalte geleert und die ToDo Spalte wieder aufgefüllt.&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;Das Backlog Board (siehe unten im Titelbild) ist Gedacht für Aufgaben in dem Zeitraum von 2 - 6 Wochen und umfasst alle Tickets die noch nicht im Aktuellen Sprint Board sind. Hier werden diese gesammelt und Stück für Stück verfeinert. Dafür existieren die vier Spalten von links nach rechts Backlog, Ready for Sizing, Ready for Sprint und Next Sprint.&lt;/p&gt;
&lt;p&gt;In jeder Spalte wird also das Ticket verfeinert z.B. wenn das Ticket von Backlog in Ready for Sizing gelangt muss es für alle Entwickler soweit verständlich sein, dass es gesized werden kann.&lt;/p&gt;
&lt;p&gt;Wenn das Ticket in die Ready for Spring Spalte kommt, ist es nun soweit fertig um potentiell in den nächsten Sprint zu gelangen. In der Spalte Next Sprint einigen wir uns darauf welche Tickets wir im nächsten Sprint abfertigen wollen.&lt;/p&gt;
&lt;h3 id=&quot;zukunft-board&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zukunft-board&quot; aria-label=&quot;zukunft 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;Zukunft Board&lt;/h3&gt;
&lt;p&gt;Das Zukunft Board ist für Ideen / Aufgaben die noch relativ unklar sind und in einem Zeitabstand von ca 6 Wochen bis hin zu einem Jahr sind. Bisher nutzen wir dieses Board noch kaum und haben Ideen in einem separiertem &lt;a href=&quot;https://miro.com&quot;&gt;Miro&lt;/a&gt; Board.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Ich bin immer noch total geflashed wie gut es mit den Tools auf GitHub es klappt in Scrum zu arbeiten. Die UI von GitHub wirkt sehr ausgeklügelt und erlaubt eine tolle Scrum Experience. Probiert es einfach mal aus :) !&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 mit Projen]]></title><description><![CDATA[Hi Projen Freunde. Projen wird immer beliebter. Ich selber nutze es schon ca seit einem halbem Jahr und bin immer noch total begeistert.…]]></description><link>https://martinmueller.dev/projen/</link><guid isPermaLink="false">https://martinmueller.dev/projen/</guid><category><![CDATA[de]]></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 Freunde.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen&lt;/a&gt; wird immer beliebter. Ich selber nutze es schon ca seit einem halbem Jahr und bin immer noch total begeistert. Kürzlich habe ich es sogar geschafft einen Docker Image Release Cycle nach Docker Hub damit zu bauen. Mein &lt;a href=&quot;https://github.com/mmuller88/influxdb-s3-backup&quot;&gt;Docker InfluxDB Repo&lt;/a&gt; pusht nun automatisch bei jedem release eine Image nach Docker Hub.&lt;/p&gt;
&lt;p&gt;Was genau Projen ist und wie ich damit mein Projekt und Image Release Cycle manage, erkläre ich den nächsten Abschnitten.&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; erlaubt eine ausgeklügelte Verwaltung von Projektkonfiguration durch Code. Mit nur wenigen Zeilen TypeScript kann ein gesamtes Repository konfiguriert werden. Hierfür ein Beispiel:&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;&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;Diese wenigen Zeilen erzeugen alle GitHub Projektfiles die das Herz begehrt. Darunter die package.json, .gitignore, tsconfig.json und noch viele viele mehr.&lt;/p&gt;
&lt;p&gt;Wirklich richtig cool ist das Projen auch mit GitHub Workflows kommt die z.B. neue Versionen publishen können nach Registries wie NPM oder PYPI. Das habe ich in einem anderen Projekt gemacht und &lt;a href=&quot;https://martinmueller.dev/alps-unified&quot;&gt;hier&lt;/a&gt; beschrieben. Für meinen Docker Image Release nach Docker Hub habe ich den Projen GitHub Release Workflow erweitert. Wie genau seht ihr im nächsten Abschnitt.&lt;/p&gt;
&lt;h1&gt;Projen Setup&lt;/h1&gt;
&lt;p&gt;Nachfolgend seht ihr meine aktuelles Projen Setup welches in dem File .projenrc.js hinterlegt ist.&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;Meine Projen Projekt ist vom Typen 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;Das bedeuted, dass es ein typisches node deployment ist, welches nodejs als environment benötigt und zusätzliches Libaries sowie Projektinformationen in der package.json enthält. Dazu kommt noch dass Node Projekte eine Changelog.md, welches alle Änderungen seit dem letzten Release auflisten können, kommt.&lt;/p&gt;
&lt;p&gt;Außerdem besitzt es einen GitHub Release Workflow welches mittels GitHub Actions automatisch GitHub releases macht bei commits und dabei die &lt;a href=&quot;https://semver.org&quot;&gt;semver&lt;/a&gt; befolgt. Ich habe nun eben genau diesen release Workflow erweitert um auch Docker Images nach Docker Hub pushen zu können in der gleichen Tagversion wie sie auch während des GitHub Releases gemacht wird. Um den Release Workflow zu erweitern habe ich das releaseWorkflow Objekt folgendermaßen erweitert:&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;Dieser GitHub workflow released also meine Image nach Docker Hub mit der gleichen Tagversion und 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;Neue releases nach GitHub und Docker Hub werden so nun komplett von Projen gemanaged und bei commits nach master automatisch durchgeführt. Das ist extrem cool und spart mir viel Zeit :).&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Ich habe das Projen Framework lieben gelernt, da es eine tolle Abstraktion und Vorgabe für ein Setup von Projekten ist. Ich lege dir ans Herz Projen mal einen Versuch zu geben und sehr bald wirst du die Schönheit dieses Frameworks selber erleben.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 - Den Gaszähler digital auslesen]]></title><description><![CDATA[Bevor es losgeht. Im Beitrag sind Affiliates bezüglich der IOT Geräte Hi. Vor einigen Wochen habe ich bereits hier mein neues IOT Deployment…]]></description><link>https://martinmueller.dev/nodered/</link><guid isPermaLink="false">https://martinmueller.dev/nodered/</guid><category><![CDATA[de]]></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;Bevor es losgeht. Im Beitrag sind Affiliates bezüglich der IOT Geräte&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;Vor einigen Wochen habe ich bereits &lt;a href=&quot;https://martinmueller.dev/rasp4&quot;&gt;hier&lt;/a&gt; mein neues IOT Deployment vorgestellt. Es besteht aus einem &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; und dem &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;. Die Software die auf dem Raspberry 4 läuft ist Docker Compose. Mit dem Docker Compose Deployment kommt für das IOT Management &lt;a href=&quot;https://github.com/node-red/node-red&quot;&gt;NodeRED&lt;/a&gt; zum Einsatz. Für die Anzeige in Diagrammen verwende ich &lt;a href=&quot;https://github.com/grafana/grafana&quot;&gt;Grafana&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Zuerst möchte ich erklären wie ich meinen analogen Gaszähler digital auslesbar gemacht habe und dann wie ich NodeRED und Grafana nutze um die erhaltenen Daten zu transformieren und in Diagramme (siehe Titelbild) anzeigbar gemacht habe.&lt;/p&gt;
&lt;h1&gt;Gaszähler Erweiterung&lt;/h1&gt;
&lt;p&gt;Wie im Bild oben rechts zu sehen habe ich einen analogen Gaszähler BK-G4. Wie also daraus einen digitalen Gaszähler der sogar Werte über Zeit speichern kann? Nun der Zähler sendet alle 0,01 qm verbrauchtem Gas einen magnetischen Impuls. Auf dem Bild ist das auch als 1 imp 0,01 qm zu sehen. Wenn also auch du einen Gaszähler mit magnetischen Impuls hast, sollte die Anleitung hier auch bei dir funktionieren.&lt;/p&gt;
&lt;p&gt;Den magnetischen Impuls messe ich einfach mit dem kabellosen &lt;a href=&quot;https://amzn.to/2KEqsAz&quot;&gt;Zigbee Türsensor&lt;/a&gt; (auch oben rechts in Bild) und sende ihn an einen &lt;a href=&quot;https://amzn.to/2Y4aq63&quot;&gt;Zigbee Empfäger&lt;/a&gt; der mit einem &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; verbunden ist und zeichne die Werte auf.&lt;/p&gt;
&lt;p&gt;Ganz so einfach ist die Aufzeichnung nicht da das Signal noch transformiert werden muss. Die Transformation des Signals wird mit NodeRED gemacht.&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; ist ein Open Source Programmiertool zum verbinden von IOT Geräten miteinander, APIs und online Services. Es bietet einen Webbrowser basierten Editor und unterstützt JavaScript als Programmiersprache. Die Runtime selbst ist &lt;a href=&quot;https://en.wikipedia.org/wiki/Node.js&quot;&gt;Nodejs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sehr cool finde ich auch, dass NodeRED eine Anbindung nach GitHub unterstützt und der aktuelle Stand des NodeRED Projektes mittels Git Protokoll versioniert abgespeichert werden kann. NodeRED bietet viele weitere tolle Funktionen, die ihr unbedingt erforschen solltet. Genauer möchte ich aber hier nur auf den NodeRED Flow eingehen.&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;Ein NodeRED Projekt kann mehrere Flows besitzen. Ein NodeRED Flow beschreibt die Interaktion von den IOT Geräten mit anderen Geräten, APIs oder online Services. Meinen Flow seht ihr oben links im Bild. Der Flow ließt sich am besten von links nach Rechts. Ganz links sind zwei Eingänge. Der untere Eingang ist von einer &lt;a href=&quot;https://openweathermap.org/appid&quot;&gt;Open Weather API&lt;/a&gt; mit der ich die aktuelle Außentemperatur erfasse (auch in dem &quot;Gas Delta&quot; Diagram in gelb zu sehen).&lt;/p&gt;
&lt;p&gt;Der obere Eingang ist von meinem Zigbee Empfänger der ja das Signal vom Zigbee Türsensor bekommt. Der Zigbee Türsensor und Empfänger arbeiten mit dem sogenannten MQTT Protokoll. MQTT is ein datensparsames, publish und subscribe Protokoll vorranging für die Kommunikation zwischen IOT Geräten.&lt;/p&gt;
&lt;p&gt;Ganz rechts in dem Flow sind die Ausgänge zu sehen (etwas abgeschnitten). Der blaue Ausgang ist ein NodeRED UI Element. NodeRED bietet auch die möglichkeit UI Elemente mit z.B. Sensorwerten zu rendern. Diese ist dann erreichbar z.B. unter &lt;a href=&quot;https://localhost:1880/ui&quot;&gt;https://localhost:1880/ui&lt;/a&gt; . Die braunen Ausgänge senden Daten zu einer InfluxDB die dann mit Grafana angezeigt werden.&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; ist eine Open Source time series Datenbank . Es ist in GO geschrieben und optimiert für schnellen, hochverfügbaren Speicher und Abfrage der gespeicherten Daten. Es eignet sich hervorragend für IOT Daten.&lt;/p&gt;
&lt;p&gt;Bei meinem Flow speicher ich den aktuellen Gaswert und die Temperatur in InfluxDB. InfluxDB berechnet dann selbstständig den Timestamp. Dann kann ich einfach mit dem graphischen Analysetool &lt;a href=&quot;https://github.com/grafana/grafana&quot;&gt;Grafana&lt;/a&gt; mir die Daten aus dem InfluxDB holen und flexibel anzeigen lassen (siehe Diagramme in Titelbild).&lt;/p&gt;
&lt;p&gt;Unten rechts sehe ich den aktuellen und gestrigen Tagesverbrauch. Man sieht es in dem Bild schlecht da nur gelb angezeigt wird aber ich habe unterschiedliche Farben für Farberreiche eingestellt. Von 0 - 7 qm ist grün. Dann von 7 - 14 qm is gelb und alles über 14 qm ist rot. Für eine dreiköpfige Familie ist der durchschnittliche Tagesverbrauch in etwa 7 qm, was in etwa maximal um den Faktor 2 schwankt im Sommer und Winter. Extrem cool ^^.&lt;/p&gt;
&lt;p&gt;Ganz unten links wird der Gesamtverbrauch des Gases angezeigt und darüber wie sich der Verbrauch über den Tag relativ ändert. Eine ziemlich coole Funktion von Grafana ist, dass der Zeitbereich komfortabel geändert werden kann. Als default habe ich &quot;Heute&quot; eingestellt welches mir alle Werte von 0 bis jetzt wiedergibt. Es gibt aber noch andere Zeitbereiche wie Gestern, Vorgestern, 12 std. usw. Auch lassen sich Start- und Endzeit direkt eingeben. Extrem cool!&lt;/p&gt;
&lt;h1&gt;InfluxDB AWS S3 Backup&lt;/h1&gt;
&lt;p&gt;Mittlerweile habe ich sogar eine Datenbackup Funktion eingebaut. Damit komprimiere ich meine InfluxDB Daten und speicher sie in AWS S3. AWS S3 ist ein günstiger langzeit Cloud Storage. Ich bevorzuge diese Methode da ich mir so keinen externen Speicher kaufen muss und die physische Verwaltung des Speichers AWS überlassen kann.&lt;/p&gt;
&lt;p&gt;Für das Backup habe ich eine eigene &lt;a href=&quot;https://github.com/mmuller88/influxdb-s3-backup&quot;&gt;Docker Image gebaut und release&lt;/a&gt;. Das war nötig da es noch keine Docker Image auf Docker Hub gab welche InfluxDB + AWS CLI + arm64 unterstützten. Diese konsumiere ich nun in meinem &lt;a href=&quot;https://github.com/mmuller88/rasp4&quot;&gt;rasp4 repo&lt;/a&gt; im docker-compose.yaml. Das Backup wird per default jeden morgen um 1 Uhr durchgeführt.&lt;/p&gt;
&lt;h1&gt;Ausblick&lt;/h1&gt;
&lt;p&gt;Als nächstes möchte ich mich gerne an meinen Stromzähler machen um auch diesen digital auslesen zu können.&lt;/p&gt;
&lt;p&gt;Ich will auch mehr IOT Geräte nach NodeRED migrieren da ich zurzeit noch einiges in der Cloud mit der App &quot;Smart Life&quot; am laufen habe. Die Funktionalität dort ist aber sehr beschränkt. Z.B. kann ich bereits meinen Heizboiler an- und ausschalten und das würde ich gerne mit NodeRED steuern können.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Wenn euch noch coole Idee einfallen wie ich meine Sensordaten transformieren oder visualisieren um nützliche Informationen zu generieren, lasst es mich wissen.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Langzeit Investieren mit Trading212]]></title><description><![CDATA[Bevor es los geht! In den Trading212 Link ist ein Affiliate bei dem du und ich jeweils eine Aktie geschenkt bekommen Hi, Seit November 202…]]></description><link>https://martinmueller.dev/trading212/</link><guid isPermaLink="false">https://martinmueller.dev/trading212/</guid><category><![CDATA[de]]></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;Bevor es los geht! In den Trading212 Link ist ein Affiliate bei dem du und ich jeweils eine Aktie geschenkt bekommen&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;Seit November 2020 beschäftige ich mich mit dem Thema Aktien und bin ein aktiver Nutzer der Trading App &lt;a href=&quot;https://trading212.com/invite/GvP8w4UF&quot;&gt;Trading212&lt;/a&gt;. Der Hauptgrund dafür ist, dass ich ein Konto bei der Bank nicht als ideale Form der Aufbewahrung sehe da es dort an Wert verliert.&lt;/p&gt;
&lt;p&gt;Die genaue Erklärung warum ich in Aktien investiere und wie meine Strategie aussieht, seht ihr in den nächsten Abschnitten. Nur soviel sei schon vorweg gesagt, es war ein super Entscheidung und ich habe schon nach wenigen Wochen einen höheren Wert geschaffen, als es bei einer Bank in einem Jahr möglich wäre.&lt;/p&gt;
&lt;h1&gt;Warum?&lt;/h1&gt;
&lt;p&gt;Banken bieten heutzutage nur noch einen sehr geringen Zinssatz bis maximal 2% pro Jahr an. Das kann kaum bis garnicht mit der Inflationsrate des Geldes mithalten. Anders gesagt, man verliert Kaufkraft. Um das Wort Kaufkraft besser zu verstehen, gebe ich ein kleines Beispiel. Wenn du dir 2020 noch für 100 Brötchen von 100€ leisten konntest, sind es 2021 eventuell nur noch 90 Brötchen die du dir mit 100€ kaufen kannst.&lt;/p&gt;
&lt;p&gt;Belässt man also sein Geld auf der Bank verliert man an Kaufkraft. Es sollten also andere Möglichkeiten in Betracht gezogen werden, wenn es um die Anlage von Geld geht. Eine Investition in Aktien mit möglichst niedrigem Verlustrisiko hört sich von daher ja erstmal sehr verlockend an. An dieser Stelle sei aber gesagt, dass jede Investition ein Risiko birgt und das gilt natürlich auch für Aktien. Selbst Banken können Bankrott gehen auf Kosten der Anleger, siehe Griechenland.&lt;/p&gt;
&lt;p&gt;Auch sehr spannend finde ich den Gedanken mit dem Kauf von Aktien, bestimmte Firmen zu unterstützen. Denn für Firmen ist der Aktienmarkt eine gute Gelegenheit Zinsfrei an Kapital zum investieren zu gelangen. Alternativ müsste die Firma ein zinsbelasteten Kredit bei einer Bank beantragen. Bis zu einem gewissen Grad kann ich dann selbst in Firmen investieren die ich toll finde. Toll finde ich Firmen in dem Thematiken:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Green Energy: Firmen die den Ausbau und Weiterenwicklung von erneuerbaren Energien wie Solaranlagen oder Windräder voranbringen.&lt;/li&gt;
&lt;li&gt;Quality Food: Ich bin ein überzeugter Anhänger von hochqualitativer Nahrung und finde die Themen toll wie Bio, Regional, Fair Trade.&lt;/li&gt;
&lt;li&gt;US Tech Firmen: Als Software Entwickler weiß ich natürlich viel über Tech Firmen und weiß wie nützlich und wertvoll diese für die Menschheit sind.&lt;/li&gt;
&lt;li&gt;Non-US Tech Firmen: Da ich ja selber aus Deutschland komme, möchte ich spezifisch gerne Tech Unternehmen im EU Raum unterstützen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Und ich kann mich aktiv gegen Firmen mit gewissen Thematiken entscheiden wie fossile Brennstoffe oder Alkohol als Genussmittel. Das waren jetzt meine persönlich Thematiken und die können bei dir ja ganz anders aussehen, was auch ok ist.&lt;/p&gt;
&lt;p&gt;Im nächsten Abschnitt erkläre ich, wie ich mit &lt;a href=&quot;https://trading212.com/invite/GvP8w4UF&quot;&gt;Trading212&lt;/a&gt; in Aktien investiere.&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; ist eine Internetplattform zum investieren in Aktien. Trading212 wirbt damit, keine Kommission dafür zu verlangen, was die Plattform sehr attraktiv macht. Benutzt man einen Broker*innen verlangen diese üblicherweise eine Kommission. Trading212 besitzen auch jeweils eine ios und Android App sowie natürlich eine Weboberfläche.&lt;/p&gt;
&lt;p&gt;Ich selber nutze die Trading212 ios App sowie die Weboberfläche und bin sehr zufrieden. Damit ist es sehr einfach in Aktien zu investieren und dessen Verlauf langfristig zu verfolgen. Auch das Ein- und Auszahlen von meinem Bankkonto in meinen Trading212 Account geht sehr einfach und geht schnell.&lt;/p&gt;
&lt;p&gt;Letztes Jahr (2020) wurde ein tolles Feature mit Namen &lt;a href=&quot;https://helpcentre.trading212.com/hc/en-us/articles/360009313957-Pies-AutoInvest-Introduction&quot;&gt;Pie&lt;/a&gt; released. Damit ist es möglich sogenannte Pies anzulegen in dem man bis zu 50 Aktien anzulegen. Jede Aktie bekommt kann dan einem gewissen Prozentwert zugewiesen werden. In der Summe ergeben alle Prozentwerte dann natürlich wieder 100%. Wenn du wissen möchtest was die Pies noch alles können einfach &lt;a href=&quot;https://helpcentre.trading212.com/hc/en-us/articles/360009313957-Pies-AutoInvest-Introduction&quot;&gt;hier&lt;/a&gt; klicken.&lt;/p&gt;
&lt;p&gt;Ich finde die Pies toll weil sie bei meiner low risk Strategie helfen und mir einen super Überblick verschaffen wie sich mein breites Portfolio entwickelt. Auch finde ich die Funktion &lt;a href=&quot;https://helpcentre.trading212.com/hc/en-us/articles/360009313957-Pies-AutoInvest-Introduction&quot;&gt;AutoInvest&lt;/a&gt; bei der ich monatlich einen gewissen Betrag in den Pie einzahlen kann.&lt;/p&gt;
&lt;p&gt;Recht kürzlich ist auch das &quot;Share Pie&quot; Feature dazugekommen. Damit kann man die Erstellten Pies preisgeben und andere können sehen wie mein Pie aussieht, also in welche Aktien und wieviel Prozent ich investiert habe. Konkrete Geldbeträge werden nicht preisgegeben. Und das &lt;a href=&quot;https://trading212.com/pies/l7iYcKopcsn4QkND915c7ISopbU5&quot;&gt;hier&lt;/a&gt; ist mein Pie mit einer diversen Wahl von Aktien und Firmen die ich unterstützen möchte.&lt;/p&gt;
&lt;p&gt;Auch wenn das Angebot der verfügbaren Aktien, in die investieren werden kann bei Trading212, sehr groß ist, kam es das eine oder andere mal vor, dass meine gewünschte Aktie nicht / noch nicht verfügbar war. In so einem Fall kann man aber in dem &lt;a href=&quot;https://community.trading212.com/&quot;&gt;Trading212 Community Forum&lt;/a&gt; erbitten die jeweilige Aktie mit ins Portofolio von Trading212 aufzunehmen.&lt;/p&gt;
&lt;p&gt;Die &lt;a href=&quot;https://community.trading212.com/&quot;&gt;Trading212 Forum Community&lt;/a&gt; ist der perfekte Ort wenn man mehr über Trading mit Trading212 und generell lernen möchte. Die Community dort hat mich bei meiner Investmentstrategie stark unterstützt wofür ich sehr dankbar bin. Seit kurzem hat Trading212 auch einen &lt;a href=&quot;https://discord.gg/yWy9scvP&quot;&gt;Discord Channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Auch toll ist, dass Trading212 kostenlose Webinare zum Thema Trading auf ihrer Platform (also auch Apps) sowie auf &lt;a href=&quot;https://youtube.com/user/Trading212&quot;&gt;YouTube&lt;/a&gt; anbietet. Im nächsten Abschnitt erkläre ich meine Investmentstrategie.&lt;/p&gt;
&lt;h1&gt;Meine Strategie&lt;/h1&gt;
&lt;p&gt;Ich möchte langzeit investieren (mehr als 10 Jahre) in viele verschiedene Sektoren wie IT, Materialien, Energie usw. Welche Sektoren es gibt und was diese bedeuten findet ihr &lt;a href=&quot;https://corporatefinanceinstitute.com/resources/knowledge/finance/the-sp-sectors/&quot;&gt;hier&lt;/a&gt;. Das Geld in viele verschiedene Sektoren zu investieren, anstatt in einen einzigen spezifischen Sektor, verringert das Verlustrisiko da diese Sektoren unabhängiger voneinander sind als es ein Sektor für sich wäre. Wenn man z.B. die Coronakriese betrachtet sieht man, dass der IT Sektor nicht so stark gelitten hat wie z.B. Real Estate.&lt;/p&gt;
&lt;p&gt;Moderne Internet Plattformen wie &lt;a href=&quot;https://trading212.com/invite/GvP8w4UF&quot;&gt;Trading212&lt;/a&gt; erlauben es auf den Mittelmann wie dem Broker*innen, der ja in der Regel eine Kommission verlangt, zu verzichten da gut gestaltete Plattformen es sehr einfach machen sich selber um sein Portfolio zu kümmern.&lt;/p&gt;
&lt;p&gt;Desweiteren möchte ich einen Teil meines monatlichen Einkommens automatisch mit &lt;a href=&quot;https://helpcentre.trading212.com/hc/en-us/articles/360009313957-Pies-AutoInvest-Introduction&quot;&gt;AutoInvest&lt;/a&gt; in meinen &lt;a href=&quot;https://helpcentre.trading212.com/hc/en-us/articles/360009313957-Pies-AutoInvest-Introduction&quot;&gt;Pie&lt;/a&gt; einzahlen. Somit baue ich uns über die Jahre ein gute Rücklage auf ohne viel Aufwand damit haben zu müssen.
Ich starte mit erstmal 100€ die jeden Monat automatisch überwiesen werden und erhöhe diesen Betrag ggf. in Zukunft.&lt;/p&gt;
&lt;p&gt;Da ich noch recht neu im Thema Aktien bin, werde ich ca. 20-30% des Portofolios aus &lt;a href=&quot;https://en.wikipedia.org/wiki/Exchange-traded_fund&quot;&gt;ETFs&lt;/a&gt; zusammenbauen. Und wenn meine Erfahrung über die Zeit steigt, die ETFs gegen normale Aktien austauschen. ETFs werden von professionellen Tradern verwaltet und diese Verwaltung kostet natürlich etwas. Mein langfristiges Ziel soll es sein komplett auf fremde ETFs zu verzichten, da mir Trading212 mit den Pies quasi erlaubt mir meine eigenen ETFs zu verwalten und ich somit die Kosten sparen kann.&lt;/p&gt;
&lt;h1&gt;Ausblick&lt;/h1&gt;
&lt;p&gt;Ich bin schon sehr zufrieden mit meiner aktuellen Auswahl der Aktien und werde wohl nur noch minimal nachbessern. Dann würde ich Aktien und ETFs die nicht so gut performen gegen vielversprechendere austauschen. Mal schauen.&lt;/p&gt;
&lt;p&gt;Meine Investitionen konzentrieren sich bisher hauptsächlich auf den Amerikanischen, Deutschen und Britischen Aktienmarkt und ich sollte mir Gedanken darüber machen mein Portfolio noch diverser zu machen und in andere Aktienmärkte zu investieren und wie genau ich in diese Aufteile.&lt;/p&gt;
&lt;p&gt;Sehr gespannt warte ich auf das Feature &quot;Pies in Pie&quot; das würde die Verwaltung meines Portfolios noch weiter vereinfachen. Zurzeit brauche ich immer noch eine Excel Tabelle um die übersicht zu behalten in wieviel ich in welche Sektoren investiert habe. Mit Pies in Pie würde das direkt ablesbar sein.&lt;/p&gt;
&lt;p&gt;Auch soll bald ein Exportfeature kommen, bei dem ich die Investitionen z.B. in eine Exceltabelle exportieren kann. Damit kann ich dann andere Visualisierungtools füttern um interessante Analysen zu tätigen. Konkrete Ideen habe ich aber noch nicht.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Mit Trading212 macht Investieren in Aktien Spaß. Es gibt mir alle nötigen Tools um selber mein Aktienportfolio verwalten zu können. Das ist eine tolle Alternative zu Konten zum verwahren von Geld und darüber hinaus lernt man viele nützliche Sachen über den Aktienmarkt. Seine finanzielle Intelligenz auszubauen halte ich für wichtig und richtig. Trading212 kann auch dein Einstieg sein genau das zu tun!&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 Bericht]]></title><description><![CDATA[Hi Freunde des Chaos, Der 37te Kongress hat vom 27. - 30. Dezember 2020 stattgefunden und aufgrund der Pandemie war alles remote. Somit…]]></description><link>https://martinmueller.dev/rc3/</link><guid isPermaLink="false">https://martinmueller.dev/rc3/</guid><category><![CDATA[de]]></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 Freunde des Chaos,&lt;/p&gt;
&lt;p&gt;Der 37te Kongress hat vom 27. - 30. Dezember 2020 stattgefunden und aufgrund der Pandemie war alles remote. Somit bekam der Chaos Kongress den Namen RC3. Das war meine aller erste Chaos Computer Club Veranstaltung die ich besucht habe. Wie toll die Tage waren und was ich erlebt habe, beschreibe ich in den nächsten Abschnitten.&lt;/p&gt;
&lt;h1&gt;Tag 1&lt;/h1&gt;
&lt;p&gt;Besuchte 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;Wir schreiben den 27ten Dezember 2020. Um 12:20 geht der RC3 los. Das Intro war sehr cool. Es gab eine Zusammenfassung über das Jahr 2020 und neben Corona sind viele interessante und leider auch traurige Sachen passiert auf die aufmerksam gemacht wurde. Es wurde auch gezeigt bzw. gut klar gemacht wieviel Aufwand und wieviel Leute eigentlich daran beteiligt sind den RC3 zu ermöglichen. Extrem cool.&lt;/p&gt;
&lt;p&gt;Der erste Vortrag den ich besuchte war 13 Uhr &quot;Die Geschichte der Corona Warn-App&quot;. Es war wirklich spannend zu verfolgen wie die deutsche Corona Warn-App sich entwickelt hat, da ich es kaum verfolgt hatte. Sehr cool fand ich, dass die Konferenz ja remote war und ich teilweise in 3 Streams gleichzeitig war um mir den besten raussuchen zu können. Das würde in der Realität nicht funktionieren ^^&lt;/p&gt;
&lt;p&gt;Um 14:30 fand mein Highlight Stream statt über &quot;Wie gründe ich eine Genossenschaft?&quot;. Das Thema Gründung einer Genossenschaft interessiert mich sehr, da ich mit ein paar anderen Entwicklern gerade dabei bin eine zu gründen. Von daher war es echt cool im Detail zu erfahren was eine Genossenschaft ist und über Erfahrungsberichte von Leuten, die schon welche gegründet haben, zu hören. Für mich sehr interessant war, dass Genossenschaften wohl in einigen Bereichen helfen können Steuern zu sparen und das Genossenschaften wohl in der Allgemeinheit unterschätzt werden, obwohl sie etwas sehr tolles sind.&lt;/p&gt;
&lt;p&gt;Ich hab noch viele andere Streams an dem Tag besucht und es ist immer wieder toll Menschen so begeistert über ihre Themen präsentieren zu sehen.&lt;/p&gt;
&lt;p&gt;Auch extrem cool und witzig und toll war die RC3 World welches eine digitalisierte zweidimensionale Welt von dem RC3 Messegelände und mehr darstellt. Du erstellst dir dort einen kleinen Avatar und läufst zusammen mit vielen anderen in einer 2 d Welt herum. Mit den anderen kann man auch sprechen und sich gegenseitig per Webcam bestaunen wenn man nah genug zusammenkommt. Extrem witzig und cool. In der World wurden unter anderem die Chaos Spaces von Deutschland modelliert und das &lt;a href=&quot;https://hacklabor.de&quot;&gt;Hacklabor&lt;/a&gt; ist sehr gut gelungen (siehe Titelbild).&lt;/p&gt;
&lt;h1&gt;Tag 2&lt;/h1&gt;
&lt;p&gt;Besuchte 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;Heute ist Montag und der zweite Tag der rC3. Meine Highlight Stream heute war der 15:00 Uhr &quot;Hackergenossenschaft als Plattform chaosnahen Wirtschaftens&quot; . Da ich selber gerade bei einer Genossenschaftsgründung dabei bin, ist es hochspannend darüber zu hören. Etwas verstörend fand ich, dass die dort vorgestellte Hackergenossenschaft ein Jahr gebraucht hat um die Genossenschaft zu gründen. Das soll wohl viel mit der Bürokratie von Deutschland zu tun haben. Ich bin aber optimistisch das unsere Genossenschaftsgründung schneller gehen wird.&lt;/p&gt;
&lt;p&gt;Auch sehr spannend wer der 19:00 &quot;Gesundheit ist eine soziale Frage&quot; talks, welcher sehr schön aufgezeigt hat wie das aktuelle Deutsche Gesundheitsystem kränkelt. Z.B. das Präventation eine eher untergeordnete Rolle spielt. Auch sehr zum Nachdenken hat mich gebrachte die Formulierung warum man eigentlich Patienten wieder in ihr Umfeld entlässt, welches sie so krank gemacht hat. Genau da müsste man eigentlich ansetzen und das Umfeld / die Lebensbedingungen des Patienten angehen.&lt;/p&gt;
&lt;h1&gt;Tag 3&lt;/h1&gt;
&lt;p&gt;Besuchte 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;Heute hatte ich leider nicht ganz so viel Zeit zum Anschauen von Streams da ich an Projekten gearbeitet habe. Gegen Abends hab ich in der rC3 World etwas sozialised. Ich habe ein paar coole Dudes von dem Rostocker Space kennengelernt. Mir ist dann aufgefallen das ich Einige noch aus meiner Zeit als Rostocker Student her kenne. Die rC3 World ist dann auch irgendwann zusammengebrochen und es hat sehr lange gedauert bis diese wieder erreichbar war.&lt;/p&gt;
&lt;h1&gt;Tag 4&lt;/h1&gt;
&lt;p&gt;Heute konnte ich so gut wie keine Streams besuchen da viel auf Arbeit getan werden musste. Ich konnte gegen Abend aber noch etwas Zeit mit Freunden in der World verbringen und ein ein paar Streams schauen.&lt;/p&gt;
&lt;h1&gt;Fazit&lt;/h1&gt;
&lt;p&gt;Vielen vielen Dank an die Organisator und mitwirkenden Kräfte des rC3. Es war meine aller erste Chaos Computer Club Veranstaltung und es hat mich einfach aus den Socken gehauen. Es gab viele spannende Streams und die World war genial. Dafür dass dies die erste rC3 war, sind die relativ häufigen technische Markel / Ausfälle auf jedenfall verzeihbar.&lt;/p&gt;
&lt;p&gt;Anyhow ich hoffe für 2021 findet die C3 wieder in Person statt, aber falls nicht die rC3 ist eine super Alternative! Danke auch an meinen Kumpel und erfahrenen C3 Kongress Besucher für die vielen kleinen Tipps und das lustige Beisammen sein die meine rC3 Experience super gemacht hat :).&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 mit AWS CDK Pipeline automatisiertes Deployment]]></title><description><![CDATA[Hi Raspberry Freunde. Hinweis: Ich habe in diesem Artikel Provisions-Links verwendet und sie durch "*" gekennzeichnet. Seit kurzem darf ich…]]></description><link>https://martinmueller.dev/rasp4/</link><guid isPermaLink="false">https://martinmueller.dev/rasp4/</guid><category><![CDATA[de]]></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 Freunde.&lt;/p&gt;
&lt;p&gt;Hinweis: Ich habe in diesem Artikel Provisions-Links verwendet und sie durch &quot;*&quot; gekennzeichnet.&lt;/p&gt;
&lt;p&gt;Seit kurzem darf ich mich Besitzer eines Raspberries nennen. Am Cyber Monday habe ich mir einen *&lt;a href=&quot;https://amzn.to/3rD3HOf&quot;&gt;Raspberry 4 mit 4 GB&lt;/a&gt; gekauft. Ich habe schon früher Erfahrungen mit Home IOT gesammelt und diese in einem &lt;a href=&quot;https://martinmueller.dev/smart-home-de&quot;&gt;Blogpost&lt;/a&gt; zusammengefasst. Allerdings waren diese Erfahrungen an fertige IOT Lösungen gebunden und geben daher nur einen limitierten Funktionsumfang. Ein guter Freund von mir, der viel Erfahrung mit Home IOT (Internet of Things) hat, zeigte mir was noch alles so möglich ist.&lt;/p&gt;
&lt;p&gt;Ich wollte aus auf das nächste IOT Level und mit Hilfe von MQTT und NodeRED coole Lösungen bauen. Meine erster Use Case ist, dass ich den Gaszähler digital auslesen möchte und in Relation zur Zeit schöne Auswertungsgrafiken angezeigt bekomme. Im Internet fand ich eine Anleitung wie man meinen Gaszähler, digital unterstützt, auslesen kann &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;. Diese Lösung verlangte aber ein komplexes NodeRED Deployment mit der Verwendung eines Raspberries.&lt;/p&gt;
&lt;p&gt;Der Raspberry kann wie ein normale VM behandelt werden. Das heißt es wird mit einem Betriebsystem wie Ubuntu bespielt. Dann werden erforderliche Programme installiert und anschließend wird das NodeRED Deployment ausgeführt. Bei Bedarf kann die VM einfach weggeschmissen werden und alles nochmal ausgeführt werden. Das sind viele manuelle Schritte die sehr zeitaufwendig und fehleranfällig sein können.&lt;/p&gt;
&lt;p&gt;Von daher habe ich mich entschlossen das gesamt Deployment zu einem hohen Grade zu automatisieren mit der Verwendung folgender Technologien GitHub, Docker, Docker Compose, AWS CodeDeploy Agent, AWS CodePipeline mit CDK Pipeline. Prinzipiell muss dann nur noch ein push zum main branch gemacht werden und das gesamte Docker Deployment baut und startet sich von allein.&lt;/p&gt;
&lt;p&gt;Wie das alles geht beschreibe ich in den nächsten Abschnitten.&lt;/p&gt;
&lt;h1&gt;Setup&lt;/h1&gt;
&lt;p&gt;Zunächst möchte ich aber gerne mein Setup beschreiben. Wie Eingangs schon erwähnt, habe ich mir zum Cyber-Monday einen Raspberry 4 (kurz Rasp4) mit 4GB gekauft *&lt;a href=&quot;https://amzn.to/3rD3HOf&quot;&gt;https://amzn.to/3rD3HOf&lt;/a&gt;. Desweiteren gab es in dem Set noch eine 64 GB microSSD.&lt;/p&gt;
&lt;p&gt;Die Installation von Ubuntu 20.04.1 war sehr einfach und ist sehr gut Dokumentiert auf &lt;a href=&quot;https://ubuntu.com/download/raspberry-pi&quot;&gt;ubuntu.com&lt;/a&gt; . Ich habe mich für den Ubuntu Server entschieden, da ich den Rasp4 als headless remote VM benutzen möchte.&lt;/p&gt;
&lt;p&gt;Zum Auslesen des Gaszählers benötigte ich noch zwei weitere Komponenten. Einen *&lt;a href=&quot;https://amzn.to/37Vsm8S&quot;&gt;Zigbee Tür-/ Fenstersensor&lt;/a&gt; und einen &lt;a href=&quot;https://amzn.to/3hrc7nd&quot;&gt;Zigbee USB-Stick als Empfänger&lt;/a&gt;. Der Sensor sendet ein Signal zum Zigbee Empfänger jedesmal wenn der Zähler 0,1 qm Gasverbrauch gemessen hat. Das ist eine spezifische Lösung für meinen Gaszähler &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;. Für euren Gaszähler ist das eventuell so nicht möglich.&lt;/p&gt;
&lt;h2 id=&quot;installation-der-umgebung&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#installation-der-umgebung&quot; aria-label=&quot;installation der umgebung permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 der Umgebung&lt;/h2&gt;
&lt;p&gt;Die IOT Programme sollen mittels Docker Compose laufen und aus meinem &lt;a href=&quot;https://github.com/mmuller88/rasp4&quot;&gt;GitHub Repo&lt;/a&gt; die Docker Compose YAML File bereitgestellt werden. Desweiteren soll das Docker Compose Deployment automatisch rebuilded und redeployed werden sobald sich was zu den main Branch gepusht wird.&lt;/p&gt;
&lt;p&gt;Um das alles zu ermöglichen werden viele Programme wie Docker, Docker Compose, Git, AWS CLI, AWS CodeDeploy Agent usw, benötigt. Um die Installation der benötigten Programme zu vereinfachen habe ich ein Script &lt;a href=&quot;https://github.com/mmuller88/rasp4/blob/master/misc/init.sh&quot;&gt;./misc/init.sh&lt;/a&gt; erstellt. Dieses wird dann einfach auf dem Rasp4 ausgeführt:&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;Wichtig noch zu erwähnen. Der Rasp4 hat nur eine one way Internetverbindung. Das heißt er hat keine öffentliche IP und ist somit von außen nicht bzw. nur schwer erreichbar. Er ist damit nur im lokalen Netz erreichbar.&lt;/p&gt;
&lt;h2 id=&quot;automatisiertes-deployment-mit-aws-codedeploy--aws-codepipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#automatisiertes-deployment-mit-aws-codedeploy--aws-codepipeline&quot; aria-label=&quot;automatisiertes deployment mit 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;Automatisiertes Deployment mit AWS CodeDeploy &amp;#x26; AWS CodePipeline&lt;/h2&gt;
&lt;p&gt;Um manuellen Aufwand so gut es geht zu verringern, habe ich mich dafür entschieden das Docker Compose Deployment zu automatisieren. Dafür verwende ich einen AWS CodeDeploy Agenten der automatisch Änderungen auf dem main Branch registriert und auf dem Rasp4 ausführt. Die Installation des AWS CodeDeploy Agents war etwas knifflig aber hat letztenende funktioniert. Der Agent wird auch mit der init.sh installiert.&lt;/p&gt;
&lt;p&gt;Um den Agenten Aktionen auf dem Rasp4 ausführen zu lassen sobald Commits auf dem main Branch passieren, muss noch eine AWS CodePipeline erstellt werden. Die AWS CodePipeline wird Konfiguriert und Verwaltet mit &lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt; . AWS CDK ist ein Open Source Framework zur Erstellung und Verwaltung von AWS Ressourcen mit Hilfe von high level Sprachen wir TypeScript oder Python. Der AWS CDK Code is ebenfalls in meinem GitHub repo und &lt;a href=&quot;https://github.com/mmuller88/rasp4/blob/master/src&quot;&gt;hier&lt;/a&gt; zu finden.&lt;/p&gt;
&lt;p&gt;Falls ich dich für das Thema AWS CDK neugierig gemacht habe, findest du auf meiner Blogseite unzählige weitere Blogposts über &lt;a href=&quot;https://martinmueller.dev/tags/cdk&quot;&gt;AWS CDK&lt;/a&gt;&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;Mein IOT Stack besteht aus den folgenden Containern NodeRED, InfluxDB, Grafana, Mosquitto und Zigbee. Die genauen Einstellungen sind in der &lt;a href=&quot;https://github.com/mmuller88/rasp4/blob/master/docker-compose.yml&quot;&gt;docker-compose&lt;/a&gt; file . Den Stack habe ich mir mit dem Docker Compose Builder von &lt;a href=&quot;https://github.com/gcgarner/IOTstack&quot;&gt;IOTstack&lt;/a&gt; zusammengebastelt.&lt;/p&gt;
&lt;p&gt;Ich empfehle euch einen der Forks vom IOTstack zu benutzen da der User gcgarner den Builder nicht mehr zu maintainen scheint.&lt;/p&gt;
&lt;h1&gt;Was hat mir besonders Spaß gemacht?&lt;/h1&gt;
&lt;p&gt;Extrem cool fand ich die einfach Installierung von Ubuntu auf meinen Rasp4. Das ging sogar ohne extra Tastatur und Monitor und nennt sich remote Installation. Dafür muss während der Image Bespielung auf der microSSD karte einfach noch das wifi Credentials mit angegeben werden. Dieser einfach Prozess hat mich irgendwie an Docker Images erinnert, die ja auch sehr leichtfüßig unterwegs sind. Extrem cool!&lt;/p&gt;
&lt;p&gt;Es ist auch ein paar mal vorgekommen, dass ich das gesamte OS neu bespielt habe um Konfigurationsprobleme zu lösen. Da ich alle Schritte der Installation in der init.sh hatte, war das kein Problem.&lt;/p&gt;
&lt;p&gt;Auch die Erstellung der AWS CodePipeline mit AWS CDK war extrem cool. Da ich mit AWS CDK schon sehr viel Erfahrung habe, ging das sehr leicht von der Hand. Infrastructure as Code ist einfach toll!&lt;/p&gt;
&lt;h1&gt;Schwierigkeiten&lt;/h1&gt;
&lt;p&gt;Sehr zeitaufwendig und nervig war das Einrichten des AWS CodeDeploy Agents, da dieser nur mit bestimmten Programmversionen von awscli oder ruby funktioniert. Bis heute bin ich mir nicht sicher, warum der Agent immer so viel rumgezickt hat. Naja er funktioniert jetzt und das ist was zählt.&lt;/p&gt;
&lt;h1&gt;Ausblick&lt;/h1&gt;
&lt;p&gt;Ich habe bereits begonnen mit dem NodeRED Flow und kann erfolgreich den Zigbee Türsensor auslesen und bei jedem Signal den digitalen Zählerstand erhöhen. Was jetzt noch fehlt ist das Einspeisen in die InfluxDB und das Konfigurieren von Grafana um schöne Auswertungsdiagramme für gewünschte Zeiträume zu bekommen.&lt;/p&gt;
&lt;p&gt;Auch möchte ich in Zukunft an noch spannende IOT Sachen mit coolen Use Cases arbeiten. Ich denke darüber nach einige IOT Prozesse von meiner Smart Life App in mein NodeRED zu migrieren.&lt;/p&gt;
&lt;p&gt;Der Rasp4 selbst bietet noch mehr Möglichkeiten als nur als IOT Server verwendet zu werden. Z.B. verwende ich ihn bereits als DNS Server mit &lt;a href=&quot;https://github.com/pi-hole/pi-hole&quot;&gt;Pi-Hole&lt;/a&gt;. Damit blockt er z.B. nervice DNS Queries wie Telemetrie Daten oder Werbung. Mit Sicherheit werde ich noch weitere coole Use Cases für meinen Rasp4 finden.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;IOT ist ein spannendes Thema. Fertiglösungen wie Smart Life, Alexa und co sind leicht zu installieren und versprechen früh den erwünschten Erfolg. Allerdings sind solche Fertiglösungen meistens nur sehr begrenzt in der Funktionalität. Bisher bin ich mit Smart Life ganz gut voran gekommen.&lt;/p&gt;
&lt;p&gt;Die Aufgabe den Gaszähler automatisiert auszulesen, hat aber nach einer komplexeren IOT Lösung mit einem Raspberry und NodeRED Flow verlangt. Wie diese Lösung aussieht, habe ich hier beschrieben. Es hat mir unglaublich viel Spaß gemacht an diesem IOT Projekt zu arbeiten und ich bin meinem IOT Kumpel :D extrem dankbar für die Zeit, die er aufbringt um mich dem IOT Thema näher zu bringen.&lt;/p&gt;
&lt;p&gt;Fandet ihr den Artikel interessant oder habt ihr noch Fragen? Schreibt mir doch gerne :) .&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 Helfer Library]]></title><description><![CDATA[Hi :). Der neue von mir entwickelte ALPS Converter macht es möglich eine ALPS Spezifikation (kurz Spec) zu OpenApi, GraphQL oder anderen…]]></description><link>https://martinmueller.dev/alps-unified/</link><guid isPermaLink="false">https://martinmueller.dev/alps-unified/</guid><category><![CDATA[de]]></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;Der neue von mir entwickelte &lt;a href=&quot;https://github.com/mmuller88/alps-unified-ts&quot;&gt;ALPS Converter&lt;/a&gt; macht es möglich eine ALPS Spezifikation (kurz Spec) zu OpenApi, GraphQL oder anderen APIs zu konvertieren.&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;// geladen von einer 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;Weitere tolle Features meine ALPS unified Library sind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;automatische versioniertes Releasing nach &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; und &lt;a href=&quot;https://nuget.com&quot;&gt;Nuget&lt;/a&gt; (für .NET)&lt;/li&gt;
&lt;li&gt;Typensupport&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Das GitHub Projekt wurden mit &lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen&lt;/a&gt; erstellt. Was die ALPS Api und Projen ist will ich in den nächsten Abschnitten genauer erörtern.&lt;/p&gt;
&lt;h1&gt;ALPS API&lt;/h1&gt;
&lt;p&gt;ALPS ist eine Spezifikation zur Beschreibung vom Context eines Services. ALPS kann verwendet werden als Spezifikationinput zum generieren von niedrig abstrahierten Spezifikationen wie OpenApi / Swagger, WSDL, RAML, WADL.&lt;/p&gt;
&lt;p&gt;Der &lt;a href=&quot;https://github.com/mmuller88/alps-unified-ts&quot;&gt;ALPS Converter&lt;/a&gt; convertiert also eine ALPS Api Spec in niedriger abstrahierten Api Spezifikationen. Ein Beispiel für so eine Konvertierung folgt im nächsten Abschnitt.&lt;/p&gt;
&lt;h2 id=&quot;alps-api-spec-beispiel&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#alps-api-spec-beispiel&quot; aria-label=&quot;alps api spec beispiel permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 Beispiel&lt;/h2&gt;
&lt;p&gt;Das folgende Beispiel ist eine 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;Das Element &lt;strong&gt;todoItem&lt;/strong&gt; besteht aus einer &lt;strong&gt;id&lt;/strong&gt; und einem todo string &lt;strong&gt;body&lt;/strong&gt; . Es sind drei Aktionen definiert &lt;strong&gt;todoList&lt;/strong&gt; zum listen der todo Einträge, &lt;strong&gt;todoAdd&lt;/strong&gt; zum Einfügen neuer todos und &lt;strong&gt;todoRemove&lt;/strong&gt; zum Löschen von todo Einträgen.&lt;/p&gt;
&lt;p&gt;Daraus kann der Unified Convertierer diese OpenApi Spezifikation generieren:&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;Oder auch dieses 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; erlaubt eine ausgeklügelte Verwaltung von Projektkonfiguration durch Code. Mit nur wenigen Zeilen TypeScript Code kann ein gesamtes Repository konfiguriert werden. Hierfür ein Beispiel:&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;&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;Diese wenigen Zeilen erzeugen alle GitHub Projektfiles die das Herz begehrt. Darunter die package.json, .gitignore, tsconfig.json und noch viele viele mehr.&lt;/p&gt;
&lt;p&gt;Wirklich richtig cool ist das Projen auch mit GitHub Workflows kommt die z.B. neue Versionen publishen können nach Registries wie NPM oder PYPI.&lt;/p&gt;
&lt;p&gt;Ich habe das Projen Framework lieben gelernt, da es tolle Abstraktion und Vorgabe für ein Setup von Projekten ist. Ich lege dir ans Herz Projen mal einen Versuch zu geben und sehr bald wirst du die Schönheit dieses Frameworks selber erleben.&lt;/p&gt;
&lt;h1&gt;ALPS Library in Action&lt;/h1&gt;
&lt;p&gt;Hier möchte ich nun kurz meine neue ALPS Unified Library vorstellen. Das TypeScript package kann so&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;// geladen von einer 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;// oder direct per 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;Die &lt;strong&gt;Alps.unified(...)&lt;/strong&gt; Function gibt immer einen String zurück. Je nach &lt;strong&gt;formType&lt;/strong&gt; beinhaltet der zurückgegebene String das gewünsche Format. In unserem Beispiel ist das &lt;strong&gt;FormatType.OPENAPI&lt;/strong&gt; welches OpenApi in YAML ist. Würde man nun gerne OpenAPI in JSON zurückhaben wollen, ginge auch FormatType.OPENAPI_JSON. Für die Wiedergabe des Graph QL Schemas müsste man FormatType.DSL verwenden.&lt;/p&gt;
&lt;p&gt;In Python kann die Library so benutzt werden:&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 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;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 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;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;Die Verwendung in Java und .NET sollte ähnlich aussehen.&lt;/p&gt;
&lt;p&gt;In meinem vorherigen Blogpost &lt;a href=&quot;https://martinmueller.dev/alps-cdk&quot;&gt;ALPS kombiniert mit CDK&lt;/a&gt; erkläre ich wie aus einer ALPS Spec wahlweise ein AWS Api Gateway oder AWS Appsync mit dem ALPS Todo Beispiel und der ALPS unified library erzeugen werden kann.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Eine Library mit &lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen&lt;/a&gt; zu bauen war super fun! Ich habe damit eine neue, verbesserte Version von der alps unified library gebaut. Diese kommt jetzt mit supper coolen neuen Funktionen die ich hier vorgestellt habe.&lt;/p&gt;
&lt;p&gt;Achja eine Info noch. Falls euch auch das ALPS Thema interessiert, mit der &lt;a href=&quot;https://alps.io&quot;&gt;ALPS Community&lt;/a&gt; veranstalten wir regelmäßig Community Treffen online. Dort trefft ihr spannende Leute auß aller Welt. Kommt gerne mal vorbei :) .&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 kombiniert mit AWS CDK]]></title><description><![CDATA[Hi :). AWS bietet viele spannende Api Technologien an. Solche sind z.B. das AWS Api Gateway welches eine Implementation einer REST Api ist…]]></description><link>https://martinmueller.dev/alps-cdk/</link><guid isPermaLink="false">https://martinmueller.dev/alps-cdk/</guid><category><![CDATA[de]]></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 bietet viele spannende Api Technologien an. Solche sind z.B. das AWS Api Gateway welches eine Implementation einer REST Api ist oder AWS Appsync was eine GRAPH QL Api implementiert.&lt;/p&gt;
&lt;p&gt;Jeder dieser AWS Api implementationen hat seine Vor- und Nachteile. Z.B. kann die Erstellung von Appsync schneller von der Hand gehen als das Api Gateway, allerdings wird es dann wieder komplizierter bei der Erstellung von Queries and das Graph QL. Zugegeben ich kenne mich zu wenig aus um die Vor- und Nachteile der verschieden Api Implementation in AWS gegeneiner abzuwägen, aber das muss ich jetzt auch nicht mehr!&lt;/p&gt;
&lt;p&gt;Mit meiner aufregenden Arbeit mit ALPS in Kombination mit AWS CDK, kann ich die Api frei auswählbar machen oder sogar gegeneinander austauschen und das alles auf Grundlage von einer ALPS Spezifikation (kurz Spec).&lt;/p&gt;
&lt;p&gt;Was genau eine ALPS Spec ist und wie daraus mit Hilfe von AWS CDK komplette Apis wie Api Gateway oder Appsync erstellt werden können, erkläre ich euch in den nächsten Abschnitten.&lt;/p&gt;
&lt;h1&gt;ALPS Api&lt;/h1&gt;
&lt;p&gt;ALPS ist eine Spezifikation zur Beschreibung vom Context eines Services. ALPS kann verwendet werden als Spezifikationsinput zum generieren von niedrig abstrahierten Spezifikationen wie OpenApi / Swagger, WSDL, RAML, WADL.&lt;/p&gt;
&lt;p&gt;Als ich das &lt;a href=&quot;https://www.youtube.com/watch?v=oG6-r3UdenE&quot;&gt;YouTube Video&lt;/a&gt; mit &lt;a href=&quot;https://twitter.com/mamund&quot;&gt;Mike Amundsen&lt;/a&gt; gesehen habe, fand ich die Idee von ALPS sofort cool und spannend. Wie jeder gut Entwickler liebe ich Abstraktionen und ALPS scheint eine extrem coole Abstraktion zu sein. Mir kam dan sofort die Idee ob man die ALPS Api nicht mit AWS CDK Constructen verbinden könnte. Genau das habe ich gemacht und berichte mehr im Detail darüber im nächsten Abschnitt.&lt;/p&gt;
&lt;h1&gt;AWS CDK ALPS Constructs&lt;/h1&gt;
&lt;p&gt;AWS CDK Constructs sind kurzgefasst Quellcode für Resourcen in AWS. Dafür benutzen sie abstrakte Sprachen wie TypeScript oder Python und generieren aus dem Code Cloudformation Templates welche dann auch noch mit dem AWS CDK Framework applyed werden. Wenn euch das Thema AWS CDK mehr im Detail interessiert, ich habe sehr viele Posts über &lt;a href=&quot;https://martinmueller.dev/tags/cdk&quot;&gt;CDK hier geschrieben&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Mein Ziel war es also mit Hilfe von einer ALPS Specs gezielt AWS Apis wie Api Gateway und Appsync aufbauen zu lassen. Nachfolgend zeige ich zuerst ein ALPS Spec Beispiel. Dann beschreibe ich das Construct bei dem ich aus einer ALPS Spec ein AWS Api Gateway generiere. Danach wird aus der selben ALPS Spec ein Appsync gebaut.&lt;/p&gt;
&lt;p&gt;Die beiden nachfolgenden Libraries werden automatisch nach &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;NPM&lt;/a&gt; (für JavaScript und TypeScript) und &lt;a href=&quot;https://pypi.org/&quot;&gt;PYPI&lt;/a&gt; (für Python) released. In Zukunft plane ich auch zu einem öffentlichen Maven Repository und .Net package Repository zu publishen.&lt;/p&gt;
&lt;h2 id=&quot;alps-spec-beispiel&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#alps-spec-beispiel&quot; aria-label=&quot;alps spec beispiel permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 Beispiel&lt;/h2&gt;
&lt;p&gt;Das folgende Beispiel ist eine 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; &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;Das Element &lt;strong&gt;todoItem&lt;/strong&gt; besteht aus einer &lt;strong&gt;id&lt;/strong&gt; und einem todo string &lt;strong&gt;body&lt;/strong&gt; . Es sind drei Aktionen definiert &lt;strong&gt;todoList&lt;/strong&gt; zum listen der todo Einträge, &lt;strong&gt;todoAdd&lt;/strong&gt; zum Einfügen neuer todos und &lt;strong&gt;todoRemove&lt;/strong&gt; zum Löschen von todo Einträgen.&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;Das erste ALPS CDK Construct das ich implementiert habe ist das CDK ALPS REST Api Construct in meinem &lt;a href=&quot;https://github.com/mmuller88/cdk-alps-Spec-rest-api&quot;&gt;github repo&lt;/a&gt; . Es erstellt ein AWS Api Gateway mit Hilfe des &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.SpecRestApi.html&quot;&gt;CDK SpecRestApi Constructs&lt;/a&gt;. Dieses muss dann nur noch eine aus dem ALPS generierte openApi Spec übergeben werden:&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;Das zweite ALPS CDK Construct war wesentlich spannender für mich, da ich dafür AWS Appsync als Graph QL Api verwendet habe und das noch komplett neu für mich war. Wieder allen Erwartungen war das aber sehr leicht und ich hab in wenigen Stunden das Construct hier auf &lt;a href=&quot;https://github.com/mmuller88/cdk-alps-graph-ql&quot;&gt;github&lt;/a&gt; fertigstellen können. Dabei übersetzt der ALPS compiler die ALPS Spec in das Graph QL Schema und übergabt das dem &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;Super! Wir haben nun diese zwei Constructs welche aus einer ALPS Spec AWS Apis generieren können. Jetzt müssen wir das nur noch machen :). Dafür habe ich ein neues &lt;a href=&quot;https://github.com/mmuller88/cdk-alps-constructs-demo&quot;&gt;Demo Github Repo&lt;/a&gt; erstellt.&lt;/p&gt;
&lt;p&gt;Das Demo Deployment verwendet das gleich ALPS Spec TODO Beispiel welches ich schon vorgestellt habe. Zum Speichern der TODO items wird DynamoDB verwendet:&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;Dann wird das Api Gateway und Appsync erstellt&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;Das wars. Jetzt nur noch den CDK Stack applyen mit:&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. Wir haben somit ein Api Gateway und ein Appsync erstellt auf Grundlage der ALPS Api.&lt;/p&gt;
&lt;h1&gt;Use Cases&lt;/h1&gt;
&lt;p&gt;Natürlich hab ich mir gedanken gemacht welche Use Cases für die ALPS Spec Abstraktion es geben könnte. Einige sind mir aufgefallen, während ich die CDK ALPS Constructs erstellt habe.&lt;/p&gt;
&lt;p&gt;Ich sehe es als einfachen und sicheren Weg für eine Migration vom Api Gateway zu Appsync. Die Resolver für das Graph QL könnten zum Beispiel die Lambda Integrationen von der Rest Api nutzen oder eventuell sogar komplett auf diese verzichten und für CRUD Operationen auf eine DB direkt ein Mapping.&lt;/p&gt;
&lt;p&gt;Da die ALPS Spec eine Abstraktion von z.B. Rest Api ist, sollte es möglich sein für Domaineexperten diese selber schreiben zu können. Es wäre super wenn der domainspezifische Context besser abstrahiert werden könnte und das könnte mit ALPS möglich sein. Während sich also der Domaineexperte um die Fachlichkeit kümmert, kann der Entwickler an der konkreten Api und dessen Implementation arbeiten. Somit wird eine besseres modulares Arbeiten ermöglicht.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;ALPS Api ist eine faszinierende Idee über die Abstraktion von anderen Apis wie REST, Graph QL usw. Mir persönlich hat es geholfen Graph QL besser zu verstehen da ich durch den Rückweg über den ALPS Spec einen gemeinsamen Nenner hatte. Auch die automatische Generierung des Graph QL Schemas ist super toll um ebenfalls die Api besser zu verstehen.&lt;/p&gt;
&lt;p&gt;Ich selber habe bei der Erstellung der drei Repos gemerkt, dass ich noch nicht viel über die ALPS Syntax weiß und mehr darüber lernen möchte. Wenn euch auch das ALPS Thema interessiert, schreibt mir doch. Mit der &lt;a href=&quot;https://alps.io&quot;&gt;ALPS Community&lt;/a&gt; veranstalten wir regelmäßig Community Treffen online aus aller Welt. Dort trefft ihr spannende Leute und könnt euch einbringen wenn ihr wollt :).&lt;/p&gt;
&lt;p&gt;Ich arbeite bereits an einer aufgefrischten Library zur Konvertierung der ALPS Spec zu den lower abstracted Apis &lt;a href=&quot;https://github.com/mmuller88/alps-unified-ts&quot;&gt;hier&lt;/a&gt;. Damit wird es dann noch einfacher sein ALPS unified als Library in deinem Code zu benutzen:&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;// geladen von einer 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;// oder direct per 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;Darüber hinaus soll die Library in JavaScript, TypeScript, Python, Java und .NET funktioniert und über öffentliche Registries erhältlicht sein. Mehr darüber kommt in einem separatem Blogpost. Bis dahin stay tuned!&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Dankbarkeit]]></title><description><![CDATA[Ein herzliches hallo, Da wir uns jetzt gegen das Ende von 2020 zubewegen, wollte ich gerne die Gelegenheit nutzen meine Dankbarkeit zu…]]></description><link>https://martinmueller.dev/thankful/</link><guid isPermaLink="false">https://martinmueller.dev/thankful/</guid><category><![CDATA[de]]></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;Ein herzliches hallo,&lt;/p&gt;
&lt;p&gt;Da wir uns jetzt gegen das Ende von 2020 zubewegen, wollte ich gerne die Gelegenheit nutzen meine Dankbarkeit zu zeigen. Dafür möchte ich einen ganzen Blogpost widmen :). Auch wenn es für viele anders war, für uns war 2020 das beste Jahr als Familie. Warum das so ist, werdet ihr herausfinden, wenn ihr den ganzen Post lest.&lt;/p&gt;
&lt;p&gt;In den nächsten Abschnitten liste ich meine Danksagungen chronologisch nach meinen Lebensjahren.&lt;/p&gt;
&lt;h1&gt;Gott&lt;/h1&gt;
&lt;p&gt;Der erste und größte Danke geht an Gott. Denn er ist barmherzig und großzügig. Er hat mich mit einen gesunden Geist und Körper gesegnet, was bei weitem nicht selbstverständlich ist. Auf meinem Lebensweg hat er mich begleitet und vor größerem Schaden bewahrt.&lt;/p&gt;
&lt;p&gt;Vielen Dank Gott und ich bitte dich weiterhin über mich und vor allem über meine Familie, Freunde und der Menschheit zu wachen. Nur Danke sagen reicht mir nicht! Auch 2021 möchte ich mich stärker in deiner Gemeinde angagieren.&lt;/p&gt;
&lt;p&gt;Auch wenn das nicht immer einfach ist, gibst du mir die Stärke das zu tun. Ich möchte dir Danken mein Gott.&lt;/p&gt;
&lt;h1&gt;Eltern&lt;/h1&gt;
&lt;p&gt;Vielen Dank möchte ich auch an meine Mama und Papa richten. Es sind zwei unglaublich tolle Menschen. Und vor allem sind sie herzensgut. Sie haben mir tolle Werte vermittelt. Meine Kindheit als Außenseiter war gewiss nicht leicht, aber durch die Hilfe und Zuneigung meiner Familie war es kein Problem durch diese relativ schwierige Zeit meines Lebens zu gelangen.&lt;/p&gt;
&lt;p&gt;Ganz besonders möchte ich meiner Mutter danken die maßgeblich für meine Entwicklung beigetragen hat. Für sie stand Bildung für mich und meinen Bruder immer an erster Stelle. Dafür bin ich ihr extrem dankbar, denn ohne diesen hohen Stellenwert hätte ich vielleicht meinen Traumberuf als Software Entwickler niemals gefunden.&lt;/p&gt;
&lt;p&gt;Sie ist eine herzensgute und starke Frau. Ich denke das hat mich insgeheim auch stark beeinflusst bei der Wahl meiner Frau die ebenfalls herzensgut und stark ist. Vielen Danke Mutti und Pappi.&lt;/p&gt;
&lt;h1&gt;Frau&lt;/h1&gt;
&lt;p&gt;Den Dank eine meine Frau. Wo fange ich da nur an. Ich hab soviel über das ich Dankbar sein könnte wenn es zu meiner Frau kommt. Kennengelernt habe ich sie in England. Ich war dort seit fast zwei Jahren. Nach einem Praktikum bei Alfresco, bekam ich dort eine Festanstellung und entschied, länger in England zu bleiben.&lt;/p&gt;
&lt;p&gt;Meine Frau war in England für fast einem Jahr. Sie kommt aus Brasilien und wollte unbedingt England kennen lernen. Wie der Zufall es wollte, trafen wir uns und hatten sofort eine Verbindung. Liebe auf dem ersten Blick!&lt;/p&gt;
&lt;p&gt;Alles ging dann relativ schnell. Wir ziehten zusammen in eine Wohnung und verlobten uns nur wenige Monate nachdem wir uns kennengelernt hatten. Seit dem sind es nun schon 3 wunderschöne Jahre mit ihr. Unsere Beziehung ist sehr harmonisch und ich freue mich schon auf die vielen kommenden Jahren zusamen mit ihr.&lt;/p&gt;
&lt;p&gt;Vielen Dank an meine wunderschöne, kluge und tollen Frau, dafür das du immer an meiner Seite bist und gemeinsam mit mir durch das Abenteuer Leben gehst. Ich möchte keinen Tag ohne dich mehr sein. Und auch vielen Dank das du so eine tolle Mutter bist. Unsere Tochter hat so ein riesen Glück das sie eine so tolle Mutti hat.&lt;/p&gt;
&lt;h1&gt;Kind&lt;/h1&gt;
&lt;p&gt;Ein besonderer Dank geht an meine Tochter. Sie ist noch nicht in der Lage diesen Text zu verstehen. Mal sehen vielleicht existiert dieser Blog ja noch, wenn sie es dann kann und sie freute sich vielleicht darüber. Anyway ich bin sehr stolz und glücklich dein Vater sein zu dürfen.&lt;/p&gt;
&lt;p&gt;Du schenkst mir jeden Tag erneut dein Vertrauen und ich akzeptiere jeden Tag dieses kostbare Geschenk und verspreche dir, immer zu deinem Besten zu handeln. Vielen Dank das ich dein Vater sein darf.&lt;/p&gt;
&lt;h1&gt;Allen Anderen&lt;/h1&gt;
&lt;p&gt;Hier möchte ich gerne allen Danken die auch eine eigenen Abschnitt verdient hätten aber dann der Post extrem lang wäre.&lt;/p&gt;
&lt;p&gt;Ein besonderer Dank geht an meinem Bruder. Er spielte und spielt eine wichtige Rolle in meinem Leben. Zusammen aufgewachsen waren wir beste Freunde. Wir sind zusammen durch dick und dünn gegangen während des Kindergartens und zum Teil sogar noch in der Schule. Vielen Dank.&lt;/p&gt;
&lt;p&gt;Vielen vielen Dank auch an meine nicht Kernfamilie wie meinen Tanten und Onkel sowie meinen Großeltern. Wir haben euch so unglaublich viel zu verdanken. Ihr habt meiner Frau und mir bei dem Umzug nach Deutschland stark geholfen. Ihr habt uns so toll unterstützt beim Hauskauf. Außerdem waren die vielen kleinen Unterstützungen wie Klamotten für Rebecca und die vielen kleinen Geschenke extrem hilfreich. Vielen Danke für eure Hilfe.&lt;/p&gt;
&lt;p&gt;Auch möchte ich meiner Familie aus Brasilien danken. Ich hatte das Glück diese 2018 in Brasilien zu besuchen und hoffe dass ich das wieder machen kann im Jahr 2021.&lt;/p&gt;
&lt;p&gt;Auch möchte ich meinen Exkollegen aus der Firma Alfresco und der Firma Object danken. Diese haben mich sehr geprägt und zu einem besseren Entwickler reifen lassen.&lt;/p&gt;
&lt;p&gt;Erst seit kurzem leben wir in der schönen Stadt Ludwigslust. Nicht weit von uns haben wir eine tolle junge Familie gefunden mit der wir gerne Zeit verbringen. Es sind herzensgute Menschen und liebevolle Eltern. Vielen Dank dass ihr da seit und wir euch als Freunde haben dürfen.&lt;/p&gt;
&lt;p&gt;Ganz anfänglich dankte ich Gott. Ich möchte auch Gottes Gemeinde hier in Ludwigslust Danken. Die Landeskirchliche Gemeinschaft Ludwigslust ist für mich eine wertvolle Gemeinschaft mit dem Ziel Gutes zu tun und forciert Gottes Wort zu verkünden. Vielen Dank dass ich euer Mitglied sein darf.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Dankbarkeit ist eine tolle Sache und macht das Leben schöner. Es erzeugt ein positives Gefühl für an dem der Dank gerichtet ist und demjenigen der den Dank äußert. Ich hoffe euch hat dieser etwas andere Stiel trotzdem gefallen. Schreibt mir wofür ihr dankbar seit.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 den letzten Monaten habe ich erfolgreich viel Gewicht verloren mit Optimised Fasting (übersetzt optimiertes Fasten). Pro…]]></description><link>https://martinmueller.dev/optimised-fasting/</link><guid isPermaLink="false">https://martinmueller.dev/optimised-fasting/</guid><category><![CDATA[de]]></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 den letzten Monaten habe ich erfolgreich viel Gewicht verloren mit &lt;strong&gt;Optimised Fasting&lt;/strong&gt; (übersetzt optimiertes Fasten). Pro Woche habe ich ca. 500 Gramm, also einen halben Kilo, verloren. Ich habe schon viel Erfahrungen mit Fasten wie Wasserfasten gesammelt. Optimised Fasting is eine Abwandlung vom Wasserfasten. Da diese Diät für mich so erfolgreich funktioniert, wollte ich sie euch gerne einmal vorstellen.&lt;/p&gt;
&lt;h1&gt;Disclaimer&lt;/h1&gt;
&lt;p&gt;Ihr solltet diese Diät nur ausprobieren, wenn ihr schon etwas Erfahrungen mit Low Carb oder sogar Ketosis habt. Low Carb bedeutet eine massive Reduzierung der Einnahme jeglicher Arten von Zucker. Der Mensch hat im wesentlichen zwei Stoffwechsel zur Erzeugung von Energie. Das ist zum einem der Zuckerstoffwechsel und zum anderem der Fettstoffwechsel. Beim Zuckerstoffwechsel nutzt der Körper primär Zucker zum gewinnen von Energie und beim Fettstoffwechsel nutzt er primär Fett.&lt;/p&gt;
&lt;p&gt;Wenn der Fettstoffwechsel allerdings kaum benutzt wird, verkümmert er, bzw. wird nie vernünftig ausgebaut. Beim Optimised Fasting brauchen wir aber einen stark ausgebildeten Fettstoffwechsel ansonsten können die zwei Tage an denen gefastet wird, physisch und psychisch schwierig werden, da sich der Körper nach Zucker sehnt und nie vernünftig gelernt hat mit dem eignen Körperfett mittels Fettstoffwechsel umzugehen. Es wäre also ein bisschen so wie ins kalte Wasser zu springen. Nebenwirkungen können dann sein Kopfschmerzen und extremes Hungerempfinden.&lt;/p&gt;
&lt;p&gt;Wenn ihr also glaubt noch keinen gut ausgebildeten Fettstoffwechsel zu haben, empfehle ich euch erstmal eine Low Carb Diät auszuprobieren und am Wochenende mal einen Tag rheines Wasserfasten zu erleben. Hier ist noch ein älterer Post von mir über das &lt;a href=&quot;https://martinmueller.dev/waterfasting&quot;&gt;Wasserfasten&lt;/a&gt; den ich euch wärmstens empfehlen kann.&lt;/p&gt;
&lt;p&gt;In den nächsten Abschnitten möchte ich mehr über meine neue Diätform des Optimised Fasting erzählen. Bei diesem geht es primär darum über viele Wochen kontinuierlich abzunehmen mit minimalem Aufwand.&lt;/p&gt;
&lt;h1&gt;Optimised Fasting Anleitung&lt;/h1&gt;
&lt;p&gt;Optimised Fasting besteht aus ca. 2 Tagen langem Wasserfasten. Um das Training herum ist es erlaubt Vitamine, Salze und minimal Proteine zuzuführen. Durch die Zuführung von Protein vor und nach dem Training wird quasi ein anaboles Signal für den Körper ausgeschüttet, welches hilft das Training besser und vor allem intensiver durchzuführen.&lt;/p&gt;
&lt;p&gt;Die Menge an Protein darf dabei nicht zu hoch sein, da sonst das Verdauungsystem zu viel beansprucht wird und das hinderlich für das Training wird. Ca. 25g vor und nach dem Training sollten genügen.&lt;/p&gt;
&lt;p&gt;Die Vitamine sind allgemein wichtig für den Menschen um die Körperfunktionen aufrecht zu erhalten. Der Körper kann kein oder nur kaum Salz im Körper Zwischenspeichern und daher ist es notwendig Salz nachzuliefern während des Fastens. Am einfachsten geht das, wenn man ein Lebensmittel mit hohem Salzgehalt zu sich nimmt.&lt;/p&gt;
&lt;p&gt;Ein genaues Beispiel an Lebensmittel die ich mir zuführen vor und nach dem Training liste in dem nächsten Kapitel.&lt;/p&gt;
&lt;p&gt;Ziel ist es nun das Fasten solange zu machen bis du 500 Gramm weniger als letzte Woche erreicht hast. Bei mir war das bisher immer der dritte Tag, also der Tag nach den zwei Tagen Optimised Fasting. Wenn ich die 500 Gramm erreicht habe, mache ich mir immer ein Bild mit dem Smartphone von der Wage. Somit weiß ich dann wieviel KG ich nächste Woche erreichen möchte.&lt;/p&gt;
&lt;h1&gt;Optimised Fasting Beispiel&lt;/h1&gt;
&lt;p&gt;Ich arbeite als Software Entwickler für 4 Tage die Woche. Also von Montag bis Donnerstag. Von daher beginne ich das Optimised Fasting schon am Donnerstag. Am Mittwoch Abend ist also der letzte Zeitpunkt an dem ich etwas esse.&lt;/p&gt;
&lt;p&gt;Schon am Mittwoch reduziere ich Lebensmittel mit hohem Zuckergehalt. Ich ernähre mich dann hauptsächlich nur noch von Protein und Fett. Das Hilft mir meinen Fettstoffwechsel auf die nächsten 2 Tage Fasten vorzubereiten und erleichtert den Einstieg.&lt;/p&gt;
&lt;p&gt;Donnerstag und Freitag wir dan gefastet und nur um mein morgendliches Training eine Kleinigkeit gegessen.&lt;/p&gt;
&lt;h2 id=&quot;vor-dem-training&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#vor-dem-training&quot; aria-label=&quot;vor dem 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;Vor dem Training&lt;/h2&gt;
&lt;p&gt;Ich mache mir einen grünen Tee mit einer scharfen Chilli Sauce und gepressten Zitronensaft. Dadurch erhoffe ich mir einen aufputsch Effekt und eine höhere Kalorienverbrennung des Körpers durch den erhöhten Koffeingehalt und Scharfstoffe im Chilli. Danach geht es zum Training.&lt;/p&gt;
&lt;p&gt;Mein Training morgens ist breit gefächert und sehr abwechslungsreich. Je nach Körperbefinden mache ich etwas Krafttraining, Ausdauertraining oder ein kurzes hoch intensives Training. Auch Aufwärmen und anschließende Dehnung gehört zu meinem Trainingsprogramm. Wenn ihr mehr über mein Training wissen wollt, sagt mir Bescheid :).&lt;/p&gt;
&lt;h2 id=&quot;nach-dem-training&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#nach-dem-training&quot; aria-label=&quot;nach dem 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;Nach dem Training&lt;/h2&gt;
&lt;p&gt;Esse ich eine kleine Schale voll mit Nüssen (Wallnuss, Kürbiskerne, Paranuss), Omega 3 und Vitamin D Kapseln, ein Stück schwarze Schokolade, Gummibärchen (ca. 8) und zwei Eier. Im Titelbild seht ihr auch diese Mahlzeit. Wenn ihr euch vielleicht fragt wozu die Gummibärchen. Sie enthalten relativ viel Gelatine welches ein gesundes und wichtiges Protein für den Körper ist. Außerdem sind sie lecker und der Zucker in ihnen ist zu wenig um mich aus der Ketosis zu befördern.&lt;/p&gt;
&lt;h1&gt;Was ich so toll finde am Optimised Fasting&lt;/h1&gt;
&lt;p&gt;Jede Diät ist nur dann erfolgreich wenn sie einfach umsetzbar ist und Optimised Fasting ist sehr einfach umsetzbar. Es muss ja nur zwei Tage gefastet werden und an den restlichen Tagen kann man essen wie man möchte. Es ist kein aufwendiges Vorbereiten der Mahlzeiten notwendig, da ja gefastet wird.&lt;/p&gt;
&lt;p&gt;Beim Wasserfasten hat mich schon immer das viele Salzwasser trinken genervt. Durch Optimised Fasting kann genug Salz durch den Snack nach dem Training dem Körper zugeführt werden. Es tut dann nicht mehr nötig noch extra Salz in Form von Salzwasser zu trinken.&lt;/p&gt;
&lt;p&gt;Auch cool finde ich, dass die 500 Gramm, die ich jedes Wochenende erreiche, ein sehr verlässlicher Wert sind da zu einem mein Darm größtenteils entleert ist nach zwei Tagen Fasten und das Wasser, welches durch Zuckereinlagerungen in den Muskeln zustande kam, raus ist. Somit unterliege ich weniger Wasserschwankungen während der Gewichtsaufnahme nach dem zweiten Fastentag.&lt;/p&gt;
&lt;h1&gt;Vereinfachter Einstieg&lt;/h1&gt;
&lt;p&gt;Die Durchführungen meiner bisherigen Optimised Fasting waren sehr einfach für mich da ich Fasten gewöhnt bin und mich allgemein Low Carb ernähre. Auch bin ich sehr diszipliniert was den Sport angeht und meistens morgens und abends kurze und knackige Workouts absolviere. Ich kann mir nun aber vorstellen, dass dir der Einstieg etwas schwerer fallen könnte.&lt;/p&gt;
&lt;p&gt;Für diesen Fall habe ich mir eine vereinfachte Variante überlegt. Fang die ersten zwei Wochen erstmal nur mit einem Optimised Fasting Tag an. Somit gibst du deinem Körper die Möglichkeit sich langsam an das Fasten zu gewöhnen. Vielleicht reicht bei dir ja auch schon ein Fastentag und am Folgetag hast du bereits schon 500 Gramm gewicht verloren, im Vergleich zur letzten Woche. Das wäre doch super :).&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Optimised Fasting ist eine einfach Art und Weise kontinuierlich abzunehmen. Sie ist extrem leicht umzusetzen da nur ca. zwei Tage gefastet werden müssen und in der restlichen Woche kann man essen was man möchte. Kein nerviges Vorbereiten der Mahlzeiten. Kein zählen der Kalorien.&lt;/p&gt;
&lt;p&gt;Falls Fasten oder Low Carb generell etwas für dich sind, kann ich dir nur empfehlen mal diese Art der Gewichtsreduktion auszuprobieren. Schreib mir deine Erfahrungen. Ich bin sehr gespannt :) !&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[AWS Cognito Auth Mock]]></title><description><![CDATA[Ahoi AWS'ler In meinem AWS Projekt, bei dem ich per REST API Alfresco Instanzen Starten, Stoppen und Terminieren kann, verwende ich für die…]]></description><link>https://martinmueller.dev/cdk-cognito/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-cognito/</guid><category><![CDATA[de]]></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 meinem &lt;a href=&quot;https://martinmueller.dev/alf-provisioner&quot;&gt;AWS Projekt&lt;/a&gt;, bei dem ich per REST API Alfresco Instanzen Starten, Stoppen und Terminieren kann, verwende ich für die Userverwaltung AWS Cognito als Identity Provider. Cognito macht es mir einfach neue Nutzer anzulegen und ihnen die Rechte zu geben auf die REST API zugreifen zu können.&lt;/p&gt;
&lt;p&gt;Das REST API ist mittels AWS API Gateway implementiert und ein Cognito Authorizer erlaubt den Nutzern aus dem Cognito Identity Pool auf die Endpoints zuzugreifen.&lt;/p&gt;
&lt;p&gt;Besonders wichtig ist der Cognito Authorizer da ich einen Permission Layer eingebaut habe der verhindert das Nutzer Alfresco Instanzen von anderen Nutzern Abfragen oder Manipulieren können. Prinzipiell funktioniert der Permission Layer mit den vom Cognito Authorizationsprozess zurückgegebenen User ID, wenn die Authorisation erfolgreich war.&lt;/p&gt;
&lt;p&gt;Das funktioniert super, allerdings hätte ich gerne zum testen der Funktionalität des Permission Layers automatisierte Tests. Toll wäre es wenn ich dafür Postman verwenden könnte. Leider ist das nicht möglich da der Authentisierungsprozess mit Cognito eine User Interaktion benötigt um die Credentials abzufragen.&lt;/p&gt;
&lt;p&gt;Die Lösung für mich war einen Mock Authentication Layer zu schreiben welcher das genau Verhalten des Cognito Authorizer simuliert. Dafür habe ich Middy verwendet. Was Middy ist und wie genau meine Lösung aussieht beschreibe ich in den nächsten Abschnitten.&lt;/p&gt;
&lt;h1&gt;Middy als Mock Auth Layer&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/middyjs/middy&quot;&gt;Middy&lt;/a&gt; ist ein einfaches Framework zum Bauen von Layers in Lambda Funktionen. Damit ist es möglich alle Features die nicht direkt zur Business Logik gehören in Layers zu kapseln. In meinem Fall möchte ich einen Mock Auth Layer implementieren der die Cognito Authorisation simuliert. Dieser Layer soll dann optional per Environmental Variable an und ausschaltbar sein.&lt;/p&gt;
&lt;p&gt;Der komplette Code für den Auth Layer findet ihr bei mir auf &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;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 schauen wir uns den Code mal an.&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;Ich filtere also alle Headers die mit einem bestimmten Prefix beginnen. Falls keiner gesetzt wurde verwende ich &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;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;Dann werden die Headers in den Authorizer Claims Bereich kopiert welche auch die Cognito Values enthalten würden. Somit steht meiner Lambda z.B. der authentisierte User und Rolle zu Verfügung. Wie nun die MOCK_AUTH_ Header gesetzt werden können zeige ich im nächsten Abschnitt.&lt;/p&gt;
&lt;p&gt;Am Schluss mit &lt;strong&gt;.replace(/&amp;#x26;/g, &apos;:&apos;)&lt;/strong&gt; findet noch ein kleines Symbol Replacing statt da Postman es leider nicht erlaubt Doppelpunkte &lt;strong&gt;:&lt;/strong&gt; im Header Key zu verwenden.&lt;/p&gt;
&lt;h1&gt;Lambda Unit Tests&lt;/h1&gt;
&lt;p&gt;Für meine Lambdas habe ich Unit Tests geschrieben die auch die Authorisation mitberücksichtigen sollen. Aus meinem Code picke ich mir eine Unit Test Datei auf &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; heraus und erkläre diese genauer.&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;Also wie wir hier sehen verwende ich den Mock Header &lt;strong&gt;MOCK_AUTH_cognito:username&apos;: &apos;martin&apos;&lt;/strong&gt; und &lt;strong&gt;&apos;MOCK_AUTH_cognito:groups&apos;: &apos;Admin&apos;&lt;/strong&gt; . Damit simuliere ich einfach das Authorisationsverhalten von Cognito und mache den Usernamen und die Usergruppen zur Laufzeit der Lambda bekannt. Fair enough.&lt;/p&gt;
&lt;h1&gt;Postman Tests&lt;/h1&gt;
&lt;p&gt;Natürlich sollen auch meine Postmantests den neuen Auth Mock Layer nutzen können. Auf &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; habe ich eine Postman Collection mit über 40 Requests. Die gesamte Collection wird mittels Newman nach dem Bau der DEV Umgebung als Integrationtest ausgeführt:&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;Um nun den Mock Auth Layer zu nutzen müssen einfach die Header gesetzt werden, wie auch schon bei den Unit Tests im vorherigen Abschnitt:&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;Aber eine Änderung musste ich vornehmen. Postman erlaubt es nicht einen Doppelpunkt im Header Key zu haben. Also musste ich dafür ein Symbol Replacing einbauen. Das UND Zeichen &lt;strong&gt;&amp;#x26;&lt;/strong&gt; wird im Code zum Doppelpunkt &lt;strong&gt;:&lt;/strong&gt; übersetzt.&lt;/p&gt;
&lt;p&gt;Falls dich das Thema Testen mit CDK interessiert kann ich dir meinen Blog Post von &lt;a href=&quot;https://martinmueller.dev/pipeline-testing&quot;&gt;letzter Woche&lt;/a&gt; empfehlen.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;AWS Cognito ist mega cool und schnell aufgebaut. Es ermöglicht eine Palette von tollen User Verwaltungs Funktionen. Leider ist es nicht möglich den Cognito Authorisationsprocess komplett automatisiert z.B. für automatische Tests durchzuführen. Aber das macht nichts da ich mit meinem Auth Mock Layer einfach die Authorisation von Cognito simuliere. Nun zu euch. Hat euch der Beitrag gefallen? Wollt ihr mehr wissen? Sagt mir Bescheid.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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, Kürzlich erst veröffentlichte ich einen Blogpost über die AWS CDK PipelineApp Library an der ich arbeite. Falls euch das Thema…]]></description><link>https://martinmueller.dev/pipeline-testing/</link><guid isPermaLink="false">https://martinmueller.dev/pipeline-testing/</guid><category><![CDATA[de]]></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;Kürzlich erst veröffentlichte ich einen Blogpost über die &lt;a href=&quot;https://martinmueller.dev/cdk-pipeline-lib&quot;&gt;AWS CDK PipelineApp Library&lt;/a&gt; an der ich arbeite. Falls euch das Thema AWS CDK Pipeline interessiert sollten ihr unbedingt diesen Blogpost lesen! Mittlerweile habe ich die Library schon dutzende Male in meinen Projekten verwendet und somit auch weiterentwickelt.&lt;/p&gt;
&lt;p&gt;In diesem Post möchte ich gerne darauf eingehen wie man mit meiner Library automatisierte Tests mit der Pipeline ausführen kann.&lt;/p&gt;
&lt;p&gt;Übrigens meine &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-app-pipeline&quot;&gt;CDK Library&lt;/a&gt; kann direkt genutzt werden via npm Dependency und erfordert kein npm Repository. Einfach die Dependency folgendermaßen angeben:&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; &lt;span class=&quot;token string&quot;&gt;&quot;github:mmuller88/alf-cdk-app-pipeline#v0.0.8&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;h2 id=&quot;wofür-testen-wir&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wof%C3%BCr-testen-wir&quot; aria-label=&quot;wofür testen wir permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wofür testen wir?&lt;/h2&gt;
&lt;p&gt;Im Zeitalter der schnellen Releases zu Produktion ist es unerlässlich automatisierte Tests während dem Releaseprozess in der Pipeline durchzuführen. Damit wird sichergestellt, dass alte und neue Features immer noch funktionieren.&lt;/p&gt;
&lt;h2 id=&quot;cloudformation-stack-tests&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cloudformation-stack-tests&quot; aria-label=&quot;cloudformation stack tests permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cloudformation Stack Tests&lt;/h2&gt;
&lt;p&gt;Schon im letzten Blogpost habe ich meinen Ec2 Stack vorgestellt. Nun möchte ich genauer auf den Test Part im &lt;strong&gt;testCommands&lt;/strong&gt; Property eingehen.&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;Mit dem Command &lt;code&gt;curl -Ssf $InstancePublicDnsName&lt;/code&gt; teste ich ob die Ec2 Instanz erfolgreich gestartet ist. Danach findet ein Cleanup statt mit Verwendung der AWS CLI. Dadurch das die Commands als eine Liste von Strings &lt;code&gt;string[]&lt;/code&gt; übergeben werden und sequenziell abgearbeitet wird kann der Cleanup nach dem curl Befehl noch stattfinden bevor die Teststage den nächsten Command abarbeitet oder ein Fail zurückgibt.&lt;/p&gt;
&lt;p&gt;Die Variable &lt;strong&gt;$InstancePublicDnsName&lt;/strong&gt; wurde im Ec2 Stack definiert und explizit in die Test Command gerendert. Wie es definiert wurde siehst du hier:&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;h2 id=&quot;api-gateway-tests&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#api-gateway-tests&quot; aria-label=&quot;api gateway tests permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.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 Gateway Tests&lt;/h2&gt;
&lt;p&gt;In meinem AWS API GW Stack lasse ich Postman Tests laufen. Es sind mittlerweile mehr als 40 Requests die gegen das API GW laufen und das Backend ausgiebig testen. Wenn dich Postman Tests interessieren findest du auf meiner Blogseite viele Beiträge über das Thema auf &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;Mit dem CLI Tool &lt;strong&gt;newman&lt;/strong&gt; kann die Postman Collection, welche die mehr als 40 Requests Tests enthält, ausgeführt werden. Ab &lt;code&gt;aws cloudformation ...&lt;/code&gt; erfolgt auch hier ein Aufräumen von allen übrig gebliebenen Cloudformation Stacks.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Es fühlt sich an, dass meine AWS CDK Pipeline Library nützlicher und robuster wird. Mit jedem neuen Projekt von mir schleife ich etwas an ihr und sie wird somit ein Stück ausgefeilter. Ich bin sehr gespannt wo die Reise mit meiner Library noch hingehen wird.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 - Eine Library für Staging Pipelines]]></title><description><![CDATA[Hi CDK Fans, Das Bauen von AWS CDK Pipelines macht Spaß. Seit Mitte diesen Jahres (2020) gibt es sogar eine High Level CDK Pipeline welche…]]></description><link>https://martinmueller.dev/cdk-pipeline-lib/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-pipeline-lib/</guid><category><![CDATA[de]]></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;Das Bauen von AWS CDK Pipelines macht Spaß. Seit Mitte diesen Jahres (2020) gibt es sogar eine High Level CDK Pipeline welche viele Vorteile bringt wie self-mutate, ein vereinfachtes Cross-Account Deployment und eine bessere Abstraktion von den benötigten CodeBuild Projekten.&lt;/p&gt;
&lt;p&gt;Ich habe eine &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-app-pipeline&quot;&gt;CDK Library&lt;/a&gt; entwickelt die einige Probleme Lösen soll. Wenn auch ihr auf nur einer der folgenden Probleme stoßt, müsste ihr euch unbedingt den gesamten Post durchlesen :) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maintaining der CDK Dependencies zwischen mehreren Repositories&lt;/li&gt;
&lt;li&gt;Wiederholung von Code für den Bau von CDK Apps nur um z.B. einen beliebigen Stack zu deployen&lt;/li&gt;
&lt;li&gt;Wiederholung von CDK Pipeline Code&lt;/li&gt;
&lt;li&gt;Vermissen eines einheitlichen CDK Pipeline Standards über z.B. einem Interface&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In den nächsten Abschnitten geht es um diese allgemeine Library und wie ich diese Probleme löse. Zuerst beschreibe ich wozu man überhaupt eine Pipeline braucht. Dann erkläre ich genauer die Idee hinter der Library und zum Schluss zeige ich einige Beispiele meiner Projekte welche bereits die Library verwenden.&lt;/p&gt;
&lt;p&gt;Übrigens meine &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-app-pipeline&quot;&gt;CDK Library&lt;/a&gt; kann direkt genutzt werden via npm depedency und erfordert kein npm Repository. Einfach die Dependency folgendermaßen angeben:&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; &lt;span class=&quot;token string&quot;&gt;&quot;github:mmuller88/alf-cdk-app-pipeline#v0.0.7&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;h1&gt;Wozu überhaupt eine Pipeline?&lt;/h1&gt;
&lt;p&gt;In Zeiten von modernen DevOps Praktiken ist es wichtig Änderungen in der Produktion so schnell und einfach wie möglich durchzuführen. Idealerweise geschieht das basierend auf Git Code Commits und einer Staging Pipeline. Eine Staging Pipeline führt Anpassungen auf Stages aus.&lt;/p&gt;
&lt;p&gt;In meiner Firma haben wir die vier Stages DEV, QA, PROD. Die DEV Stage ist als Entwicklungsumgebung für die Entwickler gedacht. Die QA Stage ist eine Testumgebung die möglichst ähnlich der PROD Umgebung ist. Und PROD selber ist natürlich die Produktionsumgebung welche aktiv von der Firma und unseren Kunden verwendet wird.&lt;/p&gt;
&lt;p&gt;Zum besseren Verständniss benutze ich in den nächsten Abschnitten aber nur eine DEV, PROD Stage. Die PipelineApp Library lässt sich um beliebig viele Stages erweitern.&lt;/p&gt;
&lt;h1&gt;Anforderungen&lt;/h1&gt;
&lt;p&gt;Meine CDK Pipeline Library soll einige Anforderungen erfüllen die nach Außen über ein Interface implementiert sind. Hier ist das Interface implementiert mit den &lt;strong&gt;PipelineAppProps&lt;/strong&gt; für die &lt;strong&gt;PipelineApp&lt;/strong&gt; Klasse in der 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 den nächsten Unterabschnitten erläutere ich genauer die einzelnen Properties.&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;Die PipelineApp soll ihre Stages basierend auf Git Repositories deployen. Dafür ist es notwendig das Repository und den Branch zu definieren:&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;Der &lt;strong&gt;repositoryName&lt;/strong&gt; bezieht sich auf den Namen in meinem Repository auf Github z.B. &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-ui&quot;&gt;https://github.com/mmuller88/alf-cdk-ui&lt;/a&gt; . Über die Pipeline wird mittels eines Tokens dieses Repository gepullt und als Source definiert.&lt;/p&gt;
&lt;h2 id=&quot;verwalten-von-stages&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#verwalten-von-stages&quot; aria-label=&quot;verwalten von 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;Verwalten von Stages&lt;/h2&gt;
&lt;p&gt;Es soll möglich sein zu spezifischen AWS Accounts in der jeweiligen Stage zu connecten. Die Spezifikation über den Account und der Stage soll als Parameter mitgegeben werden. Ich entwickelte das folgende 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;Hier wird eine Liste von Stage Accounts übergeben in die die Pipeline die Stacks deployen wird. Zusätzlich wird mit dem &lt;strong&gt;stage&lt;/strong&gt; property der Name der Stage festgelegt. Die Reihenfolge der Accounts bestimmt auch die Reihenfolge in der das Staging durchgeführt wird. In diesem Beispiel wird also zuerst die DEV Stage durchlaufen und dann Die PROD Stage.&lt;/p&gt;
&lt;p&gt;Der Buildaccount definiert den Account indem die CDK Pipeline deployed werden soll.&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 dem Build Account können auch wichtige Secret mit dem Secret Manager oder dem Parameter Store definiert werden wie z.B. das GitHub Token. In dem Pipeline Stack kann dann dort auf diese Secrets zugegriffen werden.&lt;/p&gt;
&lt;h2 id=&quot;ein-oder-mehrere-stacks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ein-oder-mehrere-stacks&quot; aria-label=&quot;ein oder mehrere 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;Ein oder mehrere Stacks&lt;/h2&gt;
&lt;p&gt;Die Pipeline soll in der Lage sein ein oder mehrere Stacks zu deployen und in diesige zu integrieren. Die Stackdefinition soll dabei im jeweiligen Repository liegen und kann dann einfach der Library als Higher Order Function übergeben werden:&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;Der hier aufgezeigte Stack befindet sich im &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-ec2&quot;&gt;alf-cdk-ec2&lt;/a&gt; Repo mit alf-cdk-ec2-stack.ts als File. Der Stack wird in der app.ts zusammen mit der PipelineApp Library aufgerufen.&lt;/p&gt;
&lt;p&gt;Dank der High Order Function können Account Informationen einfach als Parameter mittels &lt;strong&gt;account&lt;/strong&gt; in den jeweiligen Stage Stack integriert werden.&lt;/p&gt;
&lt;h1&gt;Library Beispiele&lt;/h1&gt;
&lt;p&gt;In diesem Abschnitt möchte ich einige Verbraucher der PipelineApp Library zeigen.&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;Das erste Beispiel handelt von einem Frontend Stack welcher eine statische Website baut. Die Technologien die ich hier verwende sind React im TypeScript Flavor. Die statische Seite wird gehostet in einem S3 Bucket mit einer davor geschalteten Cloudfront Distribution.&lt;/p&gt;
&lt;p&gt;Der gesamte Code ist auf GitHub &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-ui&quot;&gt;alf-cdk-ui&lt;/a&gt;. Im Rootverzeichniss befindet sich die React App. Im cdk folder sind alle relevanten CDK parts zu finden. Darunter das UIStack in ui-stack.ts Construct und die PipelineApp in app.ts. Die PipelineApp wird folgendermaßen aufgerufen:&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;Wie man hier sieht verwende ich für die zwei Stages dev und prod den gleichen Account. Es wäre auch möglich unterschiedliche Accounts zu verwenden. Es muss dann nur darauf geachtet werden das beim CDK Bootstrap befehl dem jeweiligen Account getrustet wird! Interessant ist das ich hier den default &lt;strong&gt;buildCommand&lt;/strong&gt; überschreibe. Die Motivation dafür ist ein Finetuning bei der Builderstellung der React App um diesen schneller zu bekommen.&lt;/p&gt;
&lt;p&gt;Der wohl interessanteste Bereich ist das &lt;strong&gt;customStack&lt;/strong&gt; Property bzw. die High Order Function. Hier wird nämlich der Stack definiert welcher von der PipelineApp verwaltet werden soll. Das ist ziemlich cool weil so die Stack Definition im UI Repo bleiben kann ich aber nur trotzdem minimal Code für die PipelineApp Library importieren muss.&lt;/p&gt;
&lt;p&gt;Ein wichtiger Punkt für die so definierten Stack wie z.B. der &lt;strong&gt;UIStack&lt;/strong&gt;. Diese sind nur erlaubt die aws-cdk Dependencies wie z.B.:&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;nur indirekt aus der PipelineApp Library laden. Das ist aber eher ein Vorteil als Nachteil da so nur noch die aws-cdk dependencies in der PipelineApp Library selbst verwaltet werden müssen. Und mit einer vernünftigen Tagging Strategie kann man aws-cdk Updateprobleme vermeiden!&lt;/p&gt;
&lt;p&gt;Der Build Command kann optional auch überschrieben werden. Hier tue ich das zum Beispiel mit &lt;strong&gt;make distcdk&lt;/strong&gt; . In den Projekten verwende ich Makefiles da diese hervorragend sind zum kapseln von Commands. Mit Makefiles habe ich auch eine schöne Übersicht von den möglichen und gewünschten Commands.&lt;/p&gt;
&lt;p&gt;Am Schluss wird über das &lt;strong&gt;testCommands&lt;/strong&gt; Property noch ein Erreichbarkeitstest durchgeführt. Der Parameter $domainName wurde im Stack so definiert:&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;Diese Notation muss so eingehalten werden, damit die PipelineApp Library nachdem Stack Deployment die Stack Output Variablen wiederfinden kann.&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;Das nächste Beispiel befindet sich in Github auf &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-ec2&quot;&gt;alf-cdk-ec2&lt;/a&gt;. Hier kreiere ein Alfresco Deployment basierend auf Docker Compose, Ec2 und CDK als Infrastrucktur Orchestrierer. Näheres könnte ihr gerne im Blog Post &lt;a href=&quot;https://martinmueller.dev/alf-cdk&quot;&gt;ACS Infrastruktur erstellen leichtgemacht mit AWS CDK&lt;/a&gt; nachlesen.&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 diesem Beispiel wird nur ein Staging Account definiert&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;Das nächste Beispiel befindet sich auch in Github &lt;a href=&quot;https://github.com/mmuller88/alf-cdk&quot;&gt;alf-cdk&lt;/a&gt;. Es ist ein sehr umfangreicher Stack bestehend aus Cognito, API GW, Lambdas, StepFunction, DynamoDB und mehr. Auch erstellt dieser Stacks andere CDK Stacks mittels einer Lambda Funktion.&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;Wie ihr seht ist das ein sehr umfangreicher Stack mit vielen Eingangs Properties. In Zukunft werde ich diesen riesen Stack eventuell etwas mehr runterbrechen. Dieses Beispiel ist in erster Linie interessant da es am Schluss ein umfangreiches Testen mit Postman und der AWS CLI macht. Das Property &lt;strong&gt;testCommands&lt;/strong&gt; führt also für die DEV Stage Postman Tests aus mit:&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;Dann löscht es alle womöglich verbliebenen CDK Stacks die durch die Tests entstanden sind mit:&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;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;CDK Codepipelines sind super cool. Allerdings auch super kompliziert bzw. komplex. Diese ganze Komplexität möchte man nicht jedesmal aufs neue bewältigen müssen nur um Stacks in eine Stagingpipeline zu pressen. Es sollte also eine gute Abstraktion zu diesen Stagingpipelines geben.&lt;/p&gt;
&lt;p&gt;In diesem Artikel habe ich eine solche Abstraktion in Form einer Library vorgestellt. Ich betreibe damit bereits einige CDK Stacks, welche hier zum vorgestellt wurden.&lt;/p&gt;
&lt;p&gt;Diese Library kann bisher nur auf Repositories in meinem Github Account zugreifen. Es wäre möglich die Library allgemeiner zu gestalten um auf beliebige Git Repositories zugreifen zu können. Wenn ihr das als nützlich anseht, sagt mir Bescheid. Jetzt bin ich aber neugierig. Was haltet ihr von meiner PipelineApp Library? Was kann ich verbessern? Lasst es mich wissen.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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, Willkommen zurück zu meiner kleinen Serie "AWS CDK Let's build a platform". In der vorherigen Folge  AWS CDK Let's build a…]]></description><link>https://martinmueller.dev/cdk-platform-api-gw/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-platform-api-gw/</guid><category><![CDATA[de]]></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;Willkommen zurück zu meiner kleinen Serie &quot;AWS CDK Let&apos;s build a platform&quot;. In der vorherigen Folge  &lt;a href=&quot;https://martinmueller.dev/cdk-platform-frontend&quot;&gt;AWS CDK Let&apos;s build a Platform - Frontend&lt;/a&gt; habe ich erklärt wie wir für meine Firma &lt;a href=&quot;https://unimed.de&quot;&gt;unimed.de&lt;/a&gt; ein cooles static React Web App mit AWS CDK bauen.&lt;/p&gt;
&lt;p&gt;AWS CDK ist ein Framework zur Erstellung und Anwendung von Cloudformation Templates. Dabei kann man zwischen gängigen Programmiersprachen wie Java, Python oder TypeScript auswählen. Wir haben uns für TypeScript entschieden. Wenn du mehr über AWS CDK wissen möchtest empfehle ich dir meine anderen Posts hier in meinem Blog wie z.B. &lt;a href=&quot;https://martinmueller.dev/cdk-example&quot;&gt;cdk-example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In dieser Folge soll es um das AWS Api Gateway gehen welches von der Frontend Applikation benutzt wird um z.B. interne Daten abzufragen oder zu speichern.&lt;/p&gt;
&lt;h1&gt;Api Gateway&lt;/h1&gt;
&lt;p&gt;Das AWS Api Gateway ist das Herzstück vieler AWS Deployments. Es ist ein Rest Api zum verarbeiten von Requests und den darauf folgenden Responses. Sollen zum Beispiel interne Daten erfragt werden könnte das mit diesem Request gemacht werden:&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;Der Response Body könnte dann folgender Maßen aussehen:&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;Das Api Gateway nimmt also ein Request entgegen, leitet es zu einer Integration weiter und gibt dann einen Response zurück. Die Integration kann dabei aus verschieden Technologien gewählt werden wie z.B. Mock, HTTP Proxy, Lambda Proxy oder anderen AWS Services. Bei der Erstellung des API Gateways haben wir uns für die Variante mit der openApi Spezifikation entschieden. Darüber hab ich ja schon in einem &lt;a href=&quot;https://martinmueller.dev/cdk-swagger&quot;&gt;vorherigen Post&lt;/a&gt; geschrieben und empfehle Euch den zu lesen.&lt;/p&gt;
&lt;p&gt;Kurz zusammengefasst bietet die Verwendung einer openApi Spezifikation einige Vorteile wie Schema Validierung der Request Parameter sowie einer tollen Dokumentation über die zu erwartenden Responses und möglichen Fehlermeldungen. Insbesondere bei der Verwendung einer NoSQL Datenbank wie DynamoDB ist die Validierung der Request Parameter extrem wichtig da ja die Datenbank selber kein Schema vorgibt! Und so sieht ein openApi Api Gateway in CDK aus:&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;Die openApi Spezifikation hier mit Namen api-gw.yaml könnte zum Beispiel so ausehen:&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; &lt;span class=&quot;token string&quot;&gt;&quot;3.0.1&quot;&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; &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; &lt;span class=&quot;token string&quot;&gt;&quot;when_no_match&quot;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;httpMethod&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;POST&quot;&lt;/span&gt;
        &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 response&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;Benutzt ihr Lambdas für eure Integrationen könnt ihr auch gleich hier dem Api Gateway erlauben auf eure Lambdas zuzugreifen:&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;Alternative könnte ihr auch bei den Lambdas selbst dem Api Gateway die Permission geben diese aufzurufen.&lt;/p&gt;
&lt;p&gt;Teil unsere Staging Pipeline, welche ich in einem der nachfolgenden Parts erläutern möchte, sind Integrationstests die nach jedem commit ausgeführt werden. Zurzeit sind es &quot;nur&quot; Postmantests die via Newman ausgeführt werden:&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;Die User Credentials werden vorher im Build per secure Environmentvariables gesetze, welche aus AWS SecurityManager geladen werden.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;In diesem Teil der &quot;AWS CDK Let&apos;s build a Platform&quot; Reihe habe ich euch erklärt wie der Backend Stack grob aussehen könnte. Was ich mit Absicht ausgelassen habe sind die Informationen was hinter dem Api Gateway bzw. den Lambdas kommt. Üblicherweise greift man hier auf Daten aus Speichern zu wie vielleicht DynamoDB oder RDS. Es kann aber auch sein, dass ihr komplexere Verarbeitungsabläufe anstoßen wollt mit AWS Step Functions.&lt;/p&gt;
&lt;p&gt;Ein tolles Beispiel wie eine CRUD Implementation mit API Gateway, Lambda und DynamoDB gemacht werden beschreibe ich bereits in einem &lt;a href=&quot;https://martinmueller.dev/cdk-example&quot;&gt;anderen Post&lt;/a&gt;. Hat auch der nächste Teile meiner &quot;AWS CDK Let&apos;s build a Platform&quot; Reihe gefallen? Was wollt ihr als nächstes wissen? Lasst es mich wissen.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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, Da ich die tolle Gelegenheit habe bei dem Bau einer Platform für meine Firma unimed.de zu helfen, will ich euch erklären wie…]]></description><link>https://martinmueller.dev/cdk-platform-frontend/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-platform-frontend/</guid><category><![CDATA[de]]></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;Da ich die tolle Gelegenheit habe bei dem Bau einer Platform für meine Firma &lt;a href=&quot;https://unimed.de&quot;&gt;unimed.de&lt;/a&gt; zu helfen, will ich euch erklären wie das aussieht. Zurzeit arbeiten wir an einer spannenden Platform zum effizienten Speichern und Auffinden von internen Daten. Meine Hauptverantwortlichkeit liegt dabei in der AWS Infrastruktur.&lt;/p&gt;
&lt;p&gt;Unser DevOps Team möchte soviel wie möglich in AWS auslagern. Für die Verwaltung der Ressourcen in AWS nutzen wir AWS CDK. AWS CDK ist ein Framework zur Erstellung und Anwendung von Cloudformation Templates. Dabei kann man zwischen gängigen Programmiersprachen auswählen. Wir haben uns für TypeScript entschieden da auch unser Frontend in TypeScript geschrieben ist und den Vorteil der starken Typendefinition mit sich bringt ohne dabei gefühlt viel an Flexibilität zu verlieren. Wenn du mehr über AWS CDK wissen möchtest empfehle ich dir meine anderen Posts hier in meinem Blog wie z.B. &lt;a href=&quot;https://martinmueller.dev/cdk-example&quot;&gt;cdk-example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Das eben erwähnte Frontend ist mit React im TypeScript Flavour implementiert. Ich plane eine mehrteilige Serie über &quot;AWS CDK Let&apos;s build a Platform&apos; und in dieser Folge geht es speziell um das Frontend.&lt;/p&gt;
&lt;h1&gt;React Frontend&lt;/h1&gt;
&lt;p&gt;Wie schon erwähnt unser Frontend is eine React Browser App im TypeScript Flavor. Sie nutzt das Material Design wo immer es möglich ist. Die Authentifizierung läuft über Keycloak welches an unser firmeninternes Active Directory angeschlossen ist. Nach dem Eingeben der Zugangsdaten kann direkt nach relevanten Daten gesucht und Neue eingefügt werden. Die static App wird mit &lt;code&gt;npm run build&lt;/code&gt; in den Ordner build gebaut.&lt;/p&gt;
&lt;p&gt;An dieser Stelle möchte ich einen Schwank auf die Infrastruktur machen. Die React Browser App ist eine Static Web App und um diese mittels AWS werden einige AWS Ressourcen benötigt. Diese möchte ich im nächsten Abschnitte Auflisten und wie sie mittel CDK verwaltet werden können.&lt;/p&gt;
&lt;h1&gt;CDK Stack&lt;/h1&gt;
&lt;p&gt;Zur Darstellung der static React App wird ein S3 Bucket benötigt, welcher als static Web App Bucket dient:&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;Ich verwende ein CDK Highlevel Construct mit Namen &lt;a href=&quot;https://www.npmjs.com/package/@mobileposse/auto-delete-bucket&quot;&gt;AutoDeleteBucket&lt;/a&gt; welcher sich bei Bedarf selbst löschen kann. Das normale &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html&quot;&gt;S3Bucket Construct&lt;/a&gt; kann die Löschung des Buckets nur durchführen wenn keine Daten in diesem Enthalten sind. Der AutDeleteBucket löscht also erst alle in im enthaltenen Daten und entfernt sich dann selbst. Dieses flexible Verhalten ist durchaus nützlich für Buckets die lediglich als static Web App Container dienen sollen. Der Name des static Web App Buckets &lt;code&gt;bucketName: ${props.subDomain}.${props.domainName}&lt;/code&gt; wird üblicherweise nach der Domain vergeben z.B. example.com .&lt;/p&gt;
&lt;p&gt;Der S3 Bucket speichert das statische Build und wird mit Cloudfront verbunden:&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 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 ist ein Cloud Distribution Network (kurz: CDN) von AWS welches die static Web Apps überall auf der Welt in den jeweiligen Regionen cashed. Somit wird die Latency während des Ladens auf ein Minimum gehalten.&lt;/p&gt;
&lt;p&gt;Um nun selbst den static Web App Build in den S3 Bucket zu laden musst noch ein BucketDeployment Construct erstellt werden:&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 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;DeployApp-&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;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 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 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;
  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; cloudfrontDistribution&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;Auch wird hier im BucketDeployment der Pfad zur Invalidierung der Cloudfront Distribution angegeben. Das sorgt dann für ein Neuladen des Cashes sofern eine neue App deployed wird. Der static Web App build Ordner enthält das Build der React App und wurde vorher mit &lt;code&gt;npm run build&lt;/code&gt; erstellt.&lt;/p&gt;
&lt;p&gt;Weiterhin wird eine Route 53 Record Resource benötigt um eine Custom Domain (z.B. &lt;a href=&quot;http://www.example.com&quot;&gt;www.example.com&lt;/a&gt;) auf den Cloudfront Endpoint zu zeigen um ein die static Web App mittels URL aufrufbar zu machen:&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;Und hier ist noch der gesamte 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 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 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 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;DeployApp-&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;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 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 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;
      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; cloudfrontDistribution&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;Wir deployen die static React App mittels einer Staging Pipeline. Das bedeutet die App durchläuft die verschieden Stages Dev, QA und Prod. Alle Stages sind separierte Accounts. Somit erreicht man eine erhöhte Sicherheit durch Trennung der Ressourcen. Der Dev Account wird zum testen neuer Features genutzt. Die QA Umgebung dient als nächste Stage.&lt;/p&gt;
&lt;p&gt;Ich würde gerne etwas ausführlicher über unsere Staging Pipeline im nächsten Teil der Serie berichten.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Eine Plattform mittels AWS zu bauen ist aufregend und macht Spaß. Die komplette Infrastruktur als Code zu haben ist extrem Vorteilhaft. Es ermöglicht ein ausgeklügeltes Staging von zum Beispiel einer Dev Environment nach QA und dann nach Prod. Des Weiteren dient der Code als Dokumentation über was genau in AWS Deployed wurde und wird. Es ist auch viel weniger fehleranfällig als alles manuelle zusammenklicken zu müssen.&lt;/p&gt;
&lt;p&gt;Hier habe ich euch den ersten Teil meiner &quot;AWS CDK Let&apos;s build a Platform&quot; Reihe vorgestellt. Ich erkläre welche Ressourcen unsere static Web App in AWS benötigt und wie diese mittels CDK verwaltet werden. Im nächsten Teil werde ich ausführlicher über unsere Staging Pipeline sprechen die quasi überall wiederverwendet wird um CDK Apps durch die verschiedenen Stages Dev, QA und Prod zu schleusen. Ich hoffe euch hat der Artikel gefallen und wenn ihr fragen habt, schreibt mir doch einfach.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 Signaturen mit Sinadura]]></title><description><![CDATA[Gesponsort bei PMGA Tech Hi Alfrescans. Digitale Signaturen sind eine der meist genutzten Formen zum Integritätscheck im Internet.…]]></description><link>https://martinmueller.dev/alf-sinadura/</link><guid isPermaLink="false">https://martinmueller.dev/alf-sinadura/</guid><category><![CDATA[de]]></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;Gesponsort bei &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;Digitale Signaturen sind eine der meist genutzten Formen zum Integritätscheck im Internet. Integritätscheck meint hier ob es sich bei dem jeweiligen Dokument um das Originale une damit keine Fälschung oder geänderten Version handelt. Ein Beispiel sind die SSL Zertifikate die zum aufrufen von HTTPS Urls benötigt werden. Dort muss quasi überprüft werden ob das SSL Zertifikat nicht gefälscht ist und das geschieht mit einer digitalen Signatur.&lt;/p&gt;
&lt;p&gt;Alfresco bietet keine Signierfunktion ootb, aber mit dem Open Source Addon &lt;a href=&quot;https://github.com/zylklab/alfresco-sinadura&quot;&gt;Sinadura&lt;/a&gt; (Repo und Share) kann diese Funktion nachgerüstet werden. Auf YouTube existiert ein kurzes &lt;a href=&quot;https://www.youtube.com/watch?feature=player_embedded&amp;#x26;v=MCTpOKZtTgw&quot;&gt;Video&lt;/a&gt; über die Signierfunktion von Sinadura. Eine Signierfunktion in Alfresco hat zwei wesentlich Vorteile. Der erste wäre eine erhöhte Sicherheit, da es so fast unmöglich gemacht wird Dokument in Alfresco zu fälschen z.B. durch einen Angreifer der ins System gelangt.&lt;/p&gt;
&lt;p&gt;Zweitens könnte somit der normale Use Case Scope, also nur innerhalb einer Firma zu bleiben, verlassen werden und Personen die nicht in der Firma arbeiten wie z.B. Kunden mit ins Content Management System mit einbezogen werden. Durch die Verwendung von Signaturen kann ein verbessertes Vertrauensverhältniss gesichert werden.&lt;/p&gt;
&lt;p&gt;In den nächsten Abschnitten möchte ich gerne mehr über das Addon Sinadura erzählen.&lt;/p&gt;
&lt;h1&gt;Sinadura Addon&lt;/h1&gt;
&lt;p&gt;Sinadura.net ist ein Open Source Projekt für digital Signatur Software. Dafür läuft normalerweise ein Sinadura Server für den Signatur Check und Erstellung. Ein Client connected sich dann zu dem Sinadura Server.&lt;/p&gt;
&lt;p&gt;Sinadura besitzt ein 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; welches bisher allerdings nur mit ACS Community und Enterprise Version 5 funktioniert. Toll wäre es natürlich auch neuere Alfresco Version ggf. mit Docker zu unterstützen. Ich habe es mir also zu Aufgabe gemacht dieses tolle Addon mit ACS 6.2 kompatibel zu machen.&lt;/p&gt;
&lt;h1&gt;ACS 6.2 Kompatibel&lt;/h1&gt;
&lt;p&gt;Aktuell basiert das 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; noch auf SDK 2.2.0 und ACS 5 . Es scheint das SDK 2.2.0 nicht mehr ootb. funktioniert und einige nötige Artefakte im Alfresco Nexus nicht mehr bereitstehen. Nur mir viel Mühe wäre es wohl möglich die Sinadura Amps noch mit SDK 2.2.0 zu kompilieren. Also habe ich mich entschlossen die neuste SDK Version 4.1.0 zu verwenden.&lt;/p&gt;
&lt;p&gt;Die Migration, welche ihr in meinem Git Repo findet unter &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;, hat super funktioniert. Wie eine Alfresco SDK 4.1.0 Build gebaut werden kann ist sehr gut beschrieben im offiziellen &lt;a href=&quot;https://github.com/Alfresco/alfresco-sdk&quot;&gt;Alfresco SDK Repo&lt;/a&gt;. SDK 4.1.0 basiert stark auf Docker und nutzt Docker Compose als Container Orchestrierer.&lt;/p&gt;
&lt;p&gt;Etwas herausfordernd war die Migration der AMP Struktur nach 4.1.0 da einige Datein nun an anderer Stelle platziert werden müssen als noch in 2.2.0 . Die sinaduraCloud war File musste ich in ein eigenständiges Tomcat mit Java 8 packen da Alfresco mit Java 11 läuftgit.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Digitale Signaturen sind ein spannendes Thema und ermöglichen einem Alfresco Document Management System komplett neue Use Cases. Auch interessant könnte der Vorgang des Signierens im Zusammenspiel mit Alfresco Process Service sein.&lt;/p&gt;
&lt;p&gt;Vielen Danke für meinen Sponsor &lt;a href=&quot;www.pmga.tech&quot;&gt;www.pmga.tech&lt;/a&gt; für die Migrations Arbeiten an Sinadura. Habt ihr spannende Alfresco Projekte an denen ihr arbeitet? Lasst es mich wissen :) !&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[ACS Infrastruktur erstellen leichtgemacht mit AWS CDK]]></title><description><![CDATA[Hi Alfrescans. Infrastruktur als Code ist in der DevOps schon länger beliebt. Als einer der ersten Vorreiter von IaC (Infrastructure as Code…]]></description><link>https://martinmueller.dev/alf-cdk/</link><guid isPermaLink="false">https://martinmueller.dev/alf-cdk/</guid><category><![CDATA[de]]></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;Infrastruktur als Code ist in der DevOps schon länger beliebt. Als einer der ersten Vorreiter von IaC (Infrastructure as Code) ist AWS mit Cloudformation. Dazu müssen Cloudformation Templates in JSON oder YAML geschrieben werden. Das funktioniert sehr gut ist aber ein zeitaufwendiger und komplexer Prozess diese Templates zu schreiben.&lt;/p&gt;
&lt;p&gt;Mit AWS CDK wurde eine neue Abstraktionsstufe über den Cloudformation Templates geschaffen, welches es so einfach wie noch nie möglich machen, die Infrastruktur für ein lauffähiges ACS bereitzustellen. In den nächsten Abschnitten erkläre ich was AWS CDK eigentlich ist und wie es helfen kann, Infrastruktur für ACS aufzubauen.&lt;/p&gt;
&lt;h1&gt;Was ist AWS CDK?&lt;/h1&gt;
&lt;p&gt;CDK steht für Cloud Development Kit und ist ein Open Software Development Framework zum Modellieren und Verwalten von Cloudformation Ressourcen und damit AWS Infrastruktur. AWS CDK synthetisiert zu Cloudformation Templates. Das bedeutet, es werden aus dem CDK Code Cloudformation Templates erstellt. Eine sogenannte CDK App besteht dabei aus einem oder mehreren Cloudformation Stacks. Es unterstützt bekannte Sprachen wie Java, Python, JavaScript oder TypeScript. Für den weiteren Verlauf dieses Artikels verwende ich TypeScript.&lt;/p&gt;
&lt;h1&gt;Warum ist CDK so toll?&lt;/h1&gt;
&lt;p&gt;Das tolle an CDK im TypeScript Flavor sind die Typendefinitionen welche ein zügiges vorankommen beim Entwickeln mit der IDEA ermöglicht, da es quasi die Dokumentation dank der Typen mit sich bringt. Ebenfalls werden durch die jahrelangen Erfahrungen mit Cloudformation bereits hervorragende Defaults gesetzt, welche Überschreibungen dieser Defaults selten nötig macht. CDK kümmert sich auch ootb. um den Upload des synthetisierten Cloudformation Template und ggf. Assets in ein S3. Ebenfalls ist das CDK Framework Open Source und falls man doch gerne etwas genauer hinschauen möchte wie CDK arbeitet, ist das einfach in GitHub möglich.&lt;/p&gt;
&lt;p&gt;AWS CDK lässt sich also hervorragend verwenden die Infrastruktur für ein ACS 6.2 Deployment bereitzustellen. Nachfolgend erkläre ich die zwei Stacks Ec2 Stack und EKS Stack, welche kreiert mit CDK kreiert wurden.&lt;/p&gt;
&lt;h1&gt;CDK Constructs&lt;/h1&gt;
&lt;p&gt;Constructs können entweder low level oder high level sein. Low level Constructs repräsentieren dabei eine Cloudformation Resource. High Level Constructs sind eine Kombination von mehreren low level Constructs. Die ganze CDK App repräsentiert dabei einen Tree an dessen Root die App selbst sind. Danach kommen die high level Constructs und als Blätter sind die low level Constructs. Interessant zu wissen, dass low level Constructs automatisch von Cloudformation Ressourcen generiert werden.&lt;/p&gt;
&lt;p&gt;Ein gutes Beispiel dafür ist das high level Construct Vpc aus dem Package @aws-cdk/aws-ec2 welches eine Kombination aus Ressourcen ist wie Vpc, InternetGateway, Cidr oder VpC Iam Role. Die Erstellung des high level VPC Construct sieht folgendermaßen aus:&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/core&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;// lediglich diese Zeile&lt;/span&gt;
  &lt;span class=&quot;token punctuation&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;Nur die Zeile &lt;code&gt;new Vpc(this, &apos;vpc&apos;);&lt;/code&gt; ist nötig um ein komplettes public VPC zu definieren. Das Gleiche in einem Cloudformation Template würde 200 Zeilen lang sein! Das wird ermöglicht dadurch das CDK extrem nützliche Default Einstellungen besitzt. Man merkt wie gut dieses Framework durch die Jahre lange Erfahrungen mit Cloudformation profitiert. Möchte man gerne ein private VPC erstellen muss nur ein drittes Parameter Objekt übergeben werden:&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;Der Code ist public und im meinem &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-ec2&quot;&gt;GitHub Repo&lt;/a&gt;. Das ACS Deployment wurde mit dem &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt; generiert und nutzt Docker Compose zur Orchestrierung der ACS Deployment Services. In dem File index.ts ist die CDK App definiert. Falls bisher noch keine CDK Apps deployed wurden muss vorher der CDK Toolkit Stack in der Ziel Region erstellt werden mit:&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;Anschließend wird der Stack wird mit dem folgenden Befehl 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;npm run build &amp;amp;&amp;amp; cdk deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Wenn alles geklappt hat, sollte die Alfresco Content App kurz ACA auf der public DNS Url erreichbar sein. Z.B.: ec2-34-201-46-76.compute-1.amazonaws.com . Diese Url kannst du direkt aus dem AWS Browser bekommen im EC2 Bereich oder du könntest eine Output Ressource für diese schreiben.&lt;/p&gt;
&lt;p&gt;Die CDK App kreiert einen Cloudformation Stack welcher eine Ec2 Instanz hinter einem Application Loadbalancer deployed. Anschließend wird der ACS Deploy Code, der auch im gleichen Repo enthalten ist, auf die Ec2 Instanz kopiert und ACS gestartet. Docker Compose dient dabei als Container Orchestrierer.&lt;/p&gt;
&lt;p&gt;Für einfach Entwicklerumgebungen ist das ideal, da sich Docker Compose Templates schnell erstellen lassen und einfach erweiterbar sind. Will man nun aber ein produktionsähnlicheres ACS Deployment erstellen, sollte Kubernetes als Container Orchestrierer verwendet werden.&lt;/p&gt;
&lt;h1&gt;EKS Stack&lt;/h1&gt;
&lt;p&gt;EKS steht für Elastic Kubernetes Service und stellt bei Nutzung eine Kubernetes Masternode bereit. Auch werden die Ec2 Workernodes konfiguriert. Im Gegensatz zum Ec2 Stack verwendet der EKS Stack Kubernetes zur Orchestrierung der ACS Deployment Services. Es gibt bereits einige gute Beispiele wie mit CDK ein EKS Deployment erstellt werden kann. &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-eks&quot;&gt;Hier&lt;/a&gt; findet ihr meinen GitHub Code. Zur Erstellung des Clusters werden folgende Properties benötigt:&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; KubernetesVersion&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;Ich überschreibe den vom CDK generierten Clusternamen mit &lt;strong&gt;clusterName&lt;/strong&gt;, da dieser nicht leserfreundlich ist. Die &lt;strong&gt;masterRole&lt;/strong&gt; erlaubt meinem IAM User Admin Zugriff zum Cluster. Die Workernode wird dann wie folge definiert:&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;
    kubernetesVersion&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;Um Alfresco per URLs erreichbar zu machen, muss noch der Ingress mit definiert werden. Ich verwende dafür einen 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;
        &lt;span class=&quot;token string-property property&quot;&gt;&apos;namespace&apos;&lt;/span&gt;&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;
        &lt;span class=&quot;token string-property property&quot;&gt;&apos;server-tokens&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 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;
        &lt;span class=&quot;token string-property property&quot;&gt;&apos;annotations&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;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 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-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;
        &lt;span class=&quot;token string-property property&quot;&gt;&apos;publishService&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;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&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;Nach erfolgreichen deployen mit&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;erscheint der folgende Output:&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;Der aws eks update-config command kann genutzt werden um zu dem Cluster zu connecten und Cluster Konfigurationen mittel kubectl anzuwenden.&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;Leider sind bis zum jetzigen Zeitpunkt noch keine der ACS Charts also Community und Enterprise mit Helm 3 kompatibel. Das bedeuted wir können nicht den existierenden HelmChart CDK Constructor verwenden um ACS zu installieren. Alternativ muss also ACS per Helm 2 installiert werden.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;AWS CDK ist ein spannendes Framework zur Erstellung von Alfresco Infrastruktur in AWS. CDK synthetisiert zu Cloudformation Templates es müssen also bestehende CI CD Pipelines kaum oder garnicht verändert werden. Dabei ist der Gewinn bei der Verwendung von CDK riesig. Z.B. die Typendefinition verhindert Bugs schon im Editor. Viele Zeilen Code werden gespart und es muss kein oder kaum YAML getemplated werden. Für mich ist CDK der nächste logische Schritt für IaC in AWS. Es gibt mittlerweile sogar die ersten Bemühungen CDK auch in das &lt;a href=&quot;https://github.com/hashicorp/terraform-cdk/&quot;&gt;Terraform&lt;/a&gt; Ökosystem zu integrieren, was ich sehr spannend finde. Schreibt mir eure Erfahrungen mit CDK :)!&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 mit Lambda]]></title><description><![CDATA[Ahoi AWS CDK Fans Beliebig viele Ec2 Instanzen mit einem Lambda zu erzeugen ist kein Problem. Möchte man aber komplexere Deployments wie z.B…]]></description><link>https://martinmueller.dev/cdk-lambda/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-lambda/</guid><category><![CDATA[de]]></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;Ahoi AWS CDK Fans&lt;/p&gt;
&lt;p&gt;Beliebig viele Ec2 Instanzen mit einem Lambda zu erzeugen ist kein Problem. Möchte man aber komplexere Deployments wie z.B. LoadBalancer, Securitygroups, Scalingroups, usw. mit einem Lambda erstellen, bieten sich auch hier CDK Apps an. Mit einem Lambda CDK Apps beliebig oft zu deployen ist aber garnicht so einfach und bisher gab es kaum Informationen dazu im Web.&lt;/p&gt;
&lt;p&gt;Während eines CDK Meetups habe ich aber den Vorschlag erhalten einfach mal ein CodeBuild Projekt zum erstellen der CDK App via Lambda zu benutzen. Und ja das hat super geklappt. In den nächsten Abschnitten stelle ich vor warum das für mich nützlich ist und wie ich das gemacht habe.&lt;/p&gt;
&lt;h1&gt;Use Cases&lt;/h1&gt;
&lt;p&gt;Schon dutzend fach erwähnt auf meiner Blogseite benutze ich CDK zum deployen meine &lt;a href=&quot;https://martinmueller.dev/alf-provisioner-eng&quot;&gt;Alfresco Provisioners&lt;/a&gt;(auch: &lt;a href=&quot;https://martinmueller.dev/cdk-solutions-constructs-2-eng&quot;&gt;CDK Construct Solutions&lt;/a&gt;). Alfresco nur auf einer EC2 VM laufen zu lassen funktioniert zwar, ist aber langfristig keine optimale Lösung. Ich wollte gerne auch in der Lage sein einen Loadbalancer und mehrere EC2 Instanzen für einen Alfresco Stack zu starten. In Zukunft will ich auch einen Kubernetes Cluster im Stack integrieren zum Orchestrieren der Instanzen bzw. Pods. Es war also nötig dieses komplexe Deployment zu verwalten und dafür bieten sich CDK Apps perfekt an.&lt;/p&gt;
&lt;p&gt;Ein anderer Use Case war für einen Kunden der gerne in der Lage sein wollte, CDK Stacks in verschiedenen Stage Accounts wie Dev, QA, Prod zu deployen. Das ganze sollte orchestriert werden mit CodePipeline. Das Deployment in den anderen Accounts auch mit CDK zu verwalten, liegt auf der Hand. Um das zu erreichen, muss auch ein CodeBuild Projekt, welches direkt CDK Befehle ausführt, erstellt werden. Dieser Use Case unterscheidet sich aber soweit, dass der Stack nicht via Lambda deployed wird, sondern via CodePipeline und CodeBuild.&lt;/p&gt;
&lt;h1&gt;CDK Deploy via CodeBuild und Lambda&lt;/h1&gt;
&lt;p&gt;Um nun mittels CDK Stacks deployen zu können, muss ein CodeBuild Projekt erstellt werden. Das Project sieht folgendermaßen aus:&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;Und so einfach gehts! So können CDK Apps mit CodeBuild innerhalb eines Accounts deployed werden. Willst du allerdings Cross Deploying machen, müssen die commands section nur leicht angepasst werden:&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;Falls du dir gerne vorher die benötigten Stack Änderungen anschauen möchtest, geht das auch ganz einfach mit:&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;Was jetzt noch fehlt ist die Lambda Implementation zur Ausführung des CodeBuild Projektes. Zuerst muss das Lambda erstellt werden:&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;Wie es schon der Lambda CDK Code andeutet, befindet sich im Folder ./lambda die Lambda Funktion:&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 und kann das Lambda selbstständig CDK Apps deployen.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;CDK macht das Erstellen und Verwalten von Stacks einfach. Das ist auch in dynamisch erstellten (z.B. mit einem Lambda) Stacks nützlich! Bei bisherigen Lösungen mussten immer erst Cloudformation Templates erstellt werden um diese anschließend in ein S3 hochladen welches dann als Source für ein Cloudformation Deploy dienen könnte.&lt;/p&gt;
&lt;p&gt;Mit der hier vorgestellten Lösung ist das nun nicht mehr notwendig und es kann sich mehr auf die Erstellung der CDK App selbst konzentriert werden. Ein weiterer Vorteil den ich sehr schätzen gelernt zu habe ist, dass ich separat die via Lambda deployten CDK Apps testen kann ohne quasi den kompletten CDK Parent Stack dafür deployen zu müssen. Das kombiniert mit CI CD Pipeline ist der wahrgewordene DevOps Traum!&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Infrastruktur Optimieren mit CDK Solutions Constructs Teil II.]]></title><description><![CDATA[Hi CDK Fans Im vorherigen Teil I habe ich das DynamoDB Stream to Lambda Solution Construct in mein Alfresco Provisioner CDK Deployment…]]></description><link>https://martinmueller.dev/cdk-solutions-constructs-2/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-solutions-constructs-2/</guid><category><![CDATA[de]]></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;Im vorherigen &lt;a href=&quot;https://martinmueller.dev/cdk-solutions-constructs&quot;&gt;Teil I&lt;/a&gt; habe ich das DynamoDB Stream to Lambda Solution Construct in mein &lt;a href=&quot;https://martinmueller.dev/alf-provisioner&quot;&gt;Alfresco Provisioner CDK Deployment&lt;/a&gt; eingebaut und den Gewinn dadurch diskutiert. Diese Woche habe ich weitere CDK Solutions Constructs integriert. CDK Solutions Constructs sind CDK Constructs welche oft genutzte Cloudformation Pattern kapseln. Näheres darüber kannst du in &lt;a href=&quot;https://martinmueller.dev/cdk-solutions-constructs&quot;&gt;Teil I&lt;/a&gt; lesen.&lt;/p&gt;
&lt;h1&gt;Cloudfront S3&lt;/h1&gt;
&lt;p&gt;Zu finden in GitHub ist das das &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. Es implementiert ein Cloudfront vorangestellt einem S3 Bucket. Dadurch können Dateien performanter verteilt werden, da sie mittels eines Content Delivery Networks gecachet und on the Edge verteilt werden. Mit dem Cloudfront S3 Solution Pattern kommen einige tolle well-architected Aspekte wie z.B. HTTP Security Headers und buckets für CDN und 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;Ich wollte dieses Pattern verwenden um die S3 Static Webside zu erweitern, da diese bereits ein Cloudfront besitzt. Allerdings unterstützt das Cloudfront S3 Solution Construct keine Static Websides. Deshalb kann ich es leider nicht für meinen Stack benutzen. Egal was zählt ist, dass ich viel über dieses Solution Construct gelernt habe und nun weiß wofür ich es nicht verwenden kann, was ja auch nützlich ist!&lt;/p&gt;
&lt;h1&gt;SQS Lambda&lt;/h1&gt;
&lt;p&gt;Das &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 ist ein spannendes Pattern welches eine Queue vom Simple Queue Service (kurz: SQS), mit einem Lambda verbindet und so die Queue Messages an das Lambda zur Weiterverarbeitung leitet. Die Queue und das Lambda bekommen dabei ausschließlich benötigten Permissions. Zusätzlich deployed das SQS Lambda Solution Construct noch eine Dead Letter Queue die zum Speichern und Weiterverarbeiten von fehlgeschlagenden Messages dient.&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;&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;
        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;Ich benötigte dieses Solution Construct da das im &lt;a href=&quot;https://martinmueller.dev/cdk-solutions-constructs&quot;&gt;Teil I&lt;/a&gt; erwähnte DynamoDB Stream to Lambda Solution Construct ein komisches Verhalten aufgewiesen hat indem es anscheinend Event Messages manchmal dupliziert. Mit dem SQS Lambda Solution Construct konnte ich eine FIFO SQS erstellen welche nun zusätzlich die im vorherigen Absatz erwähnten Vorteile besitzt.&lt;/p&gt;
&lt;h1&gt;Lambda DynamoDB&lt;/h1&gt;
&lt;p&gt;Ein simples aber dennoch tolles Solution Construct ist das &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;. Es standardisiert die Verbindung eines Lambdas zu einer DynamoDB perfekt. Bedarfsweise kann eine existierende DynamoDB Tabelle übergeben oder eine neue erstellt werden:&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;//optional existierende Tabelle übergeben&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;Als Teil des Solution Constructs werden die DynamoDB Zugriffsprivilegien and das Lambda erteilt. Ebenfalls wird nach der Erstellung oder Weiterleitung der Tabelle eine Environment Variable dem Lambda übergeben, welches den Namen der Tabelle enthält. Somit kann dann ohne jeglichen größeren Aufwand auf die Tabelle innerhalb des Lambdas zugegriffen werden:&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;// Kopiert vom 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;// Verwendung innerhalb des Lambdas&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;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Somit konnten die nächsten CDK Solution Construct erfolgreich integriert werden. Bei dem Arbeiten mit den CDK Solution Constructs stellt sich bei mir die Frage, ob es nicht auch Sinn mache eigene Solutions Constructs zu bauen. Das hätte den Vorteil der Abstraktion der Infrastruktur. Allerdings sind die Nachteile, dass eventuell nicht viel Rücksicht auf das &lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;well-architected Framework&lt;/a&gt; genommen wird.&lt;/p&gt;
&lt;p&gt;Ein weiterer Nachteil wäre, dass die selbsterstellten Solution Constructs natürlich maintained und weiter entwickelt werden sollte und das einen zusätzlichen Aufwand darstellt. Ich denke es ist so wie es oft sein sollte, der Use Case wird über die Sinnhaftigkeit der Kreierung von Solution Constructs entscheiden. Bis dahin kann und sollte man ruhig die existieren AWS CDK Solution Constructs verwenden, denn diese sind Open Source auf Git und die starke AWS Community maintained und entwickelt diese kräftig weiter. Ich konnte sogar auch schon zurück kontributieren um einen Bug zu fixen. Lasst mich wissen wie eure Erfahrungen mit den CDK Solution Constructs sind!&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Infrastruktur Optimieren mit CDK Solutions Constructs Teil I.]]></title><description><![CDATA[Ahoi AWS'ler Kürzlich wurden die ersten CDK Solution Constructs released. Sie versprechen ein neues Abstraktionslevel für CDK Constructs…]]></description><link>https://martinmueller.dev/cdk-solutions-constructs/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-solutions-constructs/</guid><category><![CDATA[de]]></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;Ahoi AWS&apos;ler&lt;/p&gt;
&lt;p&gt;Kürzlich wurden die ersten &lt;a href=&quot;https://github.com/awslabs/aws-solutions-constructs&quot;&gt;CDK Solution Constructs&lt;/a&gt; released. Sie versprechen ein neues Abstraktionslevel für CDK Constructs indem sie oft genutzte Cloudformation Patterns in eigene CDK Constructs zusammenfassen. Zum Beispiel wenn ein API GateWay mit einem Lambdaproxy verwendet werden soll, kann dafür das &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; verwendet werden.&lt;/p&gt;
&lt;p&gt;Ein toller &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; demonstriert die Kombination zweier solcher Solution Constructs sehr gut. Weiterhin versprechen die CDK Solution Constructs sich am &lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;well-architected Framework&lt;/a&gt; zu orientieren, um so zum Beispiel die fünf Pillars Operational Excellence, Security, Reliability, Performance Efficiency und Cost Optimization best möglichst mit in das CDK Deployment einzubeziehen. Das und die Einsparung an CDK Codezeilen hat mich dazu bewegt zu untersuchen ob mein &lt;a href=&quot;https://martinmueller.dev/alf-provisioner&quot;&gt;Alfresco Provisioner CDK Deployment&lt;/a&gt; von einigen CDK Solution Constructs profitieren könnten. In den nächsten Abschnitten beschreibe ich ein CDK Solution Pattern as ich erfolgreich in mein Deployment einbauen konnte.&lt;/p&gt;
&lt;h1&gt;AWS DynamoDB Stream to Lambda&lt;/h1&gt;
&lt;p&gt;Dieses Pattern, auch zu sehen 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;, beschreibt das oft verwendete Vorhaben eine DynamoDB Tabelle bei Änderungen in den Items mittels eines Streams ein Lambda aufzurufen um ggf. auf Änderungen wie Erstellen, Editieren oder Löschen reagieren zu können. Ein Beispiel dafür könnte sein, wenn das Item aus der Tabelle gelöscht wird, kann es woanders kostengünstiger persistiert werden.&lt;/p&gt;
&lt;p&gt;In mein Deployment verwende ich es direkt um die EC2 instanzen gemäß der Wunschkonfiguration in der Tabelle abzubilden. Soll nun zum Beispiel die EC2 Instanz gestoppt wird nur noch &lt;strong&gt;stopped&lt;/strong&gt; in die &lt;strong&gt;expectedStatus&lt;/strong&gt; Spalte der Tabelle geschrieben. Soll die Instanz wieder gestartet werden reicht die Änderung auf &lt;strong&gt;running&lt;/strong&gt;. Soll die Instanz komplett gelöscht werden, kann das Item einfach gelöscht werden und das gestreamte Lambda sorgt dafür, dass die Instanz gelöscht wird.&lt;/p&gt;
&lt;p&gt;Meine vorherige Lösung sah dafür die alleinige Verwendung von StepFunction vor, aber Streams dafür zu benutzen ist wesentlich vorteilhafter und spart darüber hinaus viele Zeilen Code. Auch finde ich toll, dass das Pattern den Stream weg abstrahiert und ich mir nur noch Gedanken um die Tabelle und das Lambda machen muss.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Die CDK Solution Constructs sind tolle Pattern die die Erstellung der AWS Infrastruktur massiv vereinfacht und dabei sogar das well-architected Framework mitbeachtet. Nächste Woche will ich versuchen das nächste 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; zu integrieren. Seit gespannt!&lt;/p&gt;
&lt;p&gt;Mit großer Spannung verfolge ich die Entwicklungen der CDK Solution Constructs. Habt ihr schon Erfahrungen gemacht mit CDK oder sogar schon mit den CDK Solution Constructs? Wenn ja für was? Falls ihr Fragen oder Anregungen habt, lasst es mich wissen.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 und APS Integration]]></title><description><![CDATA[Hi Alfrescans. Vor einigen Monaten berichtete ich über ein spannendes Projekt mit dem Kunden bei dem wir die neueste ACS und APS version…]]></description><link>https://martinmueller.dev/alf-acs-aps-integration/</link><guid isPermaLink="false">https://martinmueller.dev/alf-acs-aps-integration/</guid><category><![CDATA[de]]></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;Vor einigen Monaten berichtete ich über ein spannendes Projekt mit dem Kunden bei dem wir die neueste &lt;a href=&quot;https://martinmueller.dev/alf-acs-aps-integration&quot;&gt;ACS und APS version verwenden&lt;/a&gt;. Bisher lief alles reibungslos. Nun standen wir aber vor der nächsten spannenden Herausforderung. Wir wollten Prozesse in APS aus ACS heraus starten. Das Ganze aber ohne Verwendung des Share Connector, welcher normalerweise solche Integrationen zwischen ACS und APS erleichtert. Seit ACS 6.0 ist der Share Connector nicht mehr von Alfresco supported.&lt;/p&gt;
&lt;h1&gt;Problemstellung&lt;/h1&gt;
&lt;p&gt;ACS und APS sind zwei unabhängige Services die in der Lage sind über CMIS oder REST APIs miteinander zu kommunizieren. Schon seit langem ist es möglich bei APS ACS als Content Management System einzustellen und somit Daten direkt in ACS zu speichern und abrufbar (Content und Properties) zu halten. Das funktioniert super solange die Prozesse von APS aus gestartet werden. Nun kann man sich aber ja auch perfekt den Use Case vorstellen, dass Prozesse aus ACS gestartet werden sollen. Ein Beispiel dafür wäre wenn ein Dokument in einem bestimmten ACS Folder hochgeladen wird, soll ein Prozess in APS mit diesem Dokument gestartet werden.&lt;/p&gt;
&lt;p&gt;Für ACS 5.2 ließ sich das Problem mit dem Share Connector lösen. Dieser erweitert ACS mit Webscripts welche über die REST mit APS Prozesse starten kann. Zusätzlich bietet der Share Connector noch einige Share UI Erweiterungen für die APS Integration. Es wäre zwar noch möglich den Share Connector für neuere ACS Versionen zu verwenden, allerdings bietet dann Alfresco keinen Support mehr. Nachfolgend erkläre ich zwei Methoden wie ein Prozess in APS über eine URL gestartet werden kann ohne den Share Connector zu verwenden. Anschließend erkläre ich wie man diese URL in ACS als teil einer Action in Form eines Webhooks aufrufen kann.&lt;/p&gt;
&lt;h1&gt;Custom Endpoint zum Prozess Starten&lt;/h1&gt;
&lt;p&gt;APS bietet die Möglichkeit Custom Endpoints per Java Code zu implementieren. Mit diesem lassen sich dann Prozesse starten und Variablen zum Prozess übergeben. Die Alfresco Dokumentation dazu findet ihr &lt;a href=&quot;https://docs.alfresco.com/process-services1.11/topics/custom_rest_endpoints.html&quot;&gt;hier&lt;/a&gt;. Ist nun so ein Custom Endpunkt implementiert, kann dieser als WebHook in ACS genutzt werden um einen Prozess aus ACS heraus zu starten. Wie in der Dokumentation beschrieben, wird der Endpunkt mittels Java definiert um anschließend in eine Jar verpackt zu werden. Die Konfiguration dessen war etwas aufwendig da einige Dependencies nur in dem privaten Alfresco Nexus erhältlich sind. Die folgenden Dependencies habe ich benötigt um die JAR zu bauen:&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;/artifactId&amp;gt;
    &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;lt;/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;Für das private Alfresco Nexus Repository werden Zugangsdaten benötigt. Diese bekommt man unter support.alfresco.com . Anschließend kann die JAR mittels Docker in den Container kopiert werden. Nachfolgend zeige ich die Docker Compose und Docker Settings für das laden der JAR in die 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;Im Ordner ./process befindet sich die folgende Dockerfile.&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;Am besten testet ihr den Custom Endpoint zuerst mit Postman bevor ihr versucht mittels ACS Url Webhook diesen aufzurufen. Ich bin mir noch nicht sicher was diese Methode für Vorteile hat Verglichen mit der APS Signals Methode im nächsten Abschnitt. Ich vermute aber, dass mit der Java Programmierung ein komplexerer Prozessaufruf möglich sein könnte.&lt;/p&gt;
&lt;h1&gt;APS Signals für den Start des Prozess&lt;/h1&gt;
&lt;p&gt;Die Verwendung von Start Signalen in APS ist eine andere Art ACS und APS miteinander zu verbinden. Der große Vorteil gegenüber der Custom Endpoint Methode ist, dass kein Java Code erstellt werden muss und sich alles mittels UI in /activiti-app konfigurieren lässt. Ein anderer Vorteil ist, dass das sogenannte Start Signalen mehrere Prozesse staren kann. In unserem Beispiel bleibe ich aber erstmal bei einem. jtsmith beschreibt das Vorgehen sehr gut in seinem 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;. Kurz zusammengefasst wird dabei mittels APS ein Basic Auth Endpoint erstellt. Danach wird ein Signal Prozess modelliert, welcher in Zukunft das Signal quasi abfängt und auf mapped. Dafür wichtig ist, dass das Request Mapping die folgende Form haben muss:&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;Die genauen Funktionen der Properties bitte im verlinkten original Post nachlesen. Als nächstes können dann Prozesse erstellt werden die als Start Event das Signal &lt;strong&gt;mysignal&lt;/strong&gt; nutzen können umd den Prozess zu starten. Das Modell für den Signal Prozess lässt sich dann auch einfach exportieren und wiederverwenden.&lt;/p&gt;
&lt;h1&gt;ACS Webhook&lt;/h1&gt;
&lt;p&gt;In den vorherigen Abschnitten wurde erklärt wie ein APS Prozess über eine URL gestartet werden kann. Jetzt fehlt nur noch die Möglichkeit genau das zu tun mit ACS. Ich betrachte dabei den Use Case, dass ein User gerne einen Prozess gestartet haben möchte, wenn eine Datei in einem Folder in ACS hochgeladen wird. Dafür sind zwei Elemente notwendig. Für den Folder müssen wir eine Rule erstellen, welche aktiviert wenn ein neues Dokument erstellt wird. Dann muss eine WebHook Action ausgeführt werden.&lt;/p&gt;
&lt;p&gt;Leider bietet Alfresco ootb keine Webhook Action an. Es bieten sich nun als zwei Möglichkeiten. Entweder du bastelst dir selber eine Alfresco Webhook Action oder benutzt die geniale Webhook Action von &lt;a href=&quot;https://github.com/Acosix/alfresco-actions&quot;&gt;Acosix GmBH&lt;/a&gt;. Diese kommt mit vielen tollen Funktionen wie z.B. FreeMarker Text Input Felder um den Payload oder die Webhook URL zu definieren, was ziemlich cool ist. Die Webhook Action arbeitet mit Payload Templates die zur Laufzeit erstellt / angepasst werden können.&lt;/p&gt;
&lt;p&gt;Ich habe ein APS Payload Template spendiert welche bereits den vorhin erwähnten &lt;strong&gt;APS Signal Payload&lt;/strong&gt; bereitstellt. Wenn ihr noch mehr Variablen wie evtl. Alfresco Properties mittels des Webhooks übertragen wollt, muss das Payload Template nur erweitert werden in der &lt;strong&gt;variables&lt;/strong&gt; Section. Die Webhook Action von Axel bietet dabei auch hervorragende Debugging Optionen um eventuelle Bugs aufzufinden.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;ACS und APS sind mächtige Tools welche vereint Unternehmen helfen endlich die lang ersehnte, optimale digitale Lösung zu finden. Die Integration ACS nach APS stellt viele Alfresco Engineers vor Herausforderungen. Ich listete hier mehrere Möglichkeiten wie diese Integration gemeistert werden kann und hoffe das es dir hilft deine ECM BPM Ziele mittels ACS und APS zu erreichen. Unsere ACS APS Integration beim Kunden ist bei weitem noch nicht abgeschlossen, da wir planen relative komplexe Prozesse in APS zu schreiben und uns bereits gedanken über die Integrität zwischen ACS und APS machen, welches uns vor spannenden Problemen stellt. Schreibt mir wie eurer ACS APS Integration aussieht :) .&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 generierte Restic REST Serve]]></title><description><![CDATA[Hello Leute :). In diesem Beitrag möchte ich davon berichten wie einfach es sein kann einen Backend REST Server zu erstellen mit zur…]]></description><link>https://martinmueller.dev/openapi-server/</link><guid isPermaLink="false">https://martinmueller.dev/openapi-server/</guid><category><![CDATA[de]]></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 Leute :).&lt;/p&gt;
&lt;p&gt;In diesem Beitrag möchte ich davon berichten wie einfach es sein kann einen Backend REST Server zu erstellen mit zur Hilfenahme von OpenApi Spezifikationen. Mein ultimatives Ziel ist es Backups und den Restore Prozess von Alfresco Daten so einfach wie möglich zu machen. Nach langem recherchieren habe ich mich entschlossen &lt;a href=&quot;https://github.com/restic/restic&quot;&gt;Restic&lt;/a&gt; als Backup und Restoring Engine zu benutzen. Da in meinem bisherigen Deployments alle Alfresco Daten, sprich die Blob Daten, DB Daten, Solr Daten usw. im /data Folder vorliegen scheint es der perfekte Use Case für Restic zu sein. Das automatisierte Backup funktioniert so weit gut. Vielen Dank an dieser Stelle &lt;a href=&quot;https://github.com/lobaro/restic-backup-docker&quot;&gt;lobaro&lt;/a&gt; und seiner brillanten restic Backup Arbeit welche mir im Part automatisierte Backup sehr geholfen hat.&lt;/p&gt;
&lt;p&gt;Nun steht allerdings noch der Restoring part an. Und wie es scheint gibt es bisher dafür kein Tooling. Der Administrator müsste also immer die Restoring mittel Restic manuell durchführen. Das heißt in die Machine einloggen und die nötigen Restic Restore Befehle ausführen, welche den gewünschten Snapshot wiederherstellen. Diesen Prozess will ich vereinfachen und dem Administrator eine angenehme UI zur Wiederherstellung bereitstellen. Dafür verwende ich die OpenApi Technologien. In den nächsten Abschnitten erzähle ich mehr über OpenApi und was genau ich gemacht habe.&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; welches früher Swagger genannt wurde, ist eine YAML oder JSON Template Sprache zur Beschreibung von RESTful APIs. Folgend beschreibe ich was super an OpenApi ist. Erstens eigenen sich die Templates extrem gut als Dokumentation über die API selber, da aus dem Template eine schick aussehende HTML UI generiert werden kann, welche die API Endpoints sehr gut beschreibt. Eine solche UI ist im Titelbild dieses Blogposts zu sehen. Noch genialer ist die UI kann direkt zum Testen der Endpoints genutzt werden, also zum Senden und Empfangen von Requests und Responses. Viele API Schnittstellen, wie es auch AWS API Gateway eine ist, bieten es and die Parameter Validierung der Requests über OpenApi Files zu machen. Was mit Parametervalidierung gemeint ist versuche ich anhand des folgenden Beispiels zu erklären:&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;Hier ist ein Parameter vom Typ Query zu sehen sehen. Das bedeutet dieser würde in der URL in etwa so aussehen&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;Mit der Parametervalidierung kann ich dann bestimmte Eigenschaften des Parameters definieren, wie hier der name &lt;strong&gt;userId&lt;/strong&gt; ob er required ist und welchen Typ der value haben soll, in unserem Fall als vom typ string.&lt;/p&gt;
&lt;p&gt;Auch sehr mächtig ist die Eigenschaft, dass es möglich ist aus OpenApi Files &lt;a href=&quot;https://swagger.io/tools/swagger-codegen/&quot;&gt;Client Libaries und Server Stubs zu generieren&lt;/a&gt;. Alfresco generiert zum Beispiel JavaScript Clients mit zur Hilfenahme des &lt;a href=&quot;https://api-explorer.alfresco.com/api-explorer/&quot;&gt;API-Explorers&lt;/a&gt; (Näheres auf &lt;a href=&quot;https://github.com/Alfresco/rest-api-explorer&quot;&gt;GitHub Api-Explorer&lt;/a&gt;) und &lt;a href=&quot;https://www.alfresco.com/abn/adf/&quot;&gt;ADF&lt;/a&gt; (oder &lt;a href=&quot;https://github.com/Alfresco/alfresco-js-api&quot;&gt;ADF JS Github&lt;/a&gt;). Dort wird zum Beispiel aus dem &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; die eine JavaScript API Library erzeugt, welche als Wrapper für die API Requests genutzt werden kann in den &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;Auch cool ist, &lt;a href=&quot;https://www.postman.com/automated-testing&quot;&gt;Postman&lt;/a&gt; bietet eine Importierfunktion für OpenApi Files. Dann wird daraus gleich eine Collections erzeugt. Das ist sehr praktisch, wenn man anfangen möchte die Requests in Postman zu schreiben.&lt;/p&gt;
&lt;h1&gt;Server Generierung&lt;/h1&gt;
&lt;p&gt;In diesem Teil erzähle ich mehr über meine Implementierung in &lt;a href=&quot;https://github.com/mmuller88/restic-backup-restore-docker/&quot;&gt;Github&lt;/a&gt;. Der &lt;a href=&quot;https://github.com/OpenAPITools/openapi-generator-cli&quot;&gt;OpenApi Generator&lt;/a&gt; ist ein mächtiges Tool zum erzeugen von Client Libs und Server Stubs von OpenApi Spezifikationen wie der bei mir im Repo ./restic.yaml . Zurzeit interessiert mich aber lediglich die Server Stub Generierung. Es kann aus einer Reihe von verschiedenen Server Technologien wie Go, Kotlin, Java, JavaScript ausgewählt werden. Ich habe mich speziell für den NodeJS Express Server entschieden. Um den Server zu generieren wird der folgenden Befehl in ./build_server ausgeführt:&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;Ein zusätzlicher Bonus. Der NodeJS Express Server generiert auch eine Swagger UI die dann erreichbar ist auf /api-doc . Da ich bei der Servergenerierung die Handler für die Endpoints nicht immer wieder neue Implementieren möchte, habe ich diese in einem ausgewiesenem Ordner ./handlers untergebracht . Dann muss im OpenApi Spec nur noch drauf verwiesen werden:&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/DefaultController&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Das Property x-eov-operation-handler verweist auf die Handlerfunktion. Der ./handlers Ordner muss dann nur noch in die Docker Image kopiert werden.&lt;/p&gt;
&lt;h1&gt;Testing&lt;/h1&gt;
&lt;p&gt;Zum Testen verwende ich die neue GitHub Build Engine GitHub Actions bei dem Workflows generiert werden. Ich habe schon in meinem vorherigen Projekt wobeies um einen &lt;a href=&quot;https://martinmueller.dev/alf-lets-encrypt-eng&quot;&gt;Let&apos;s Encrypt SSL Docker Companion&lt;/a&gt; GitHub Actions ausgiebig getestet und für gut empfunden. In meinen Test Workflow unter ./.github/workflows/action.yml wir die Image mittels Docker Compose gestartet und ausgiebig mit zur Hilfenahme von Postman getestet. Falls du dich mehr für automatisierte Tests mit Postman interessierst klick einfach &lt;a href=&quot;https://martinmueller.dev/tags/postman&quot;&gt;hier&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Die Erstellung von REST Servern ist normalerweise ein aufwändiger Prozess, welcher das Schreiben jeder Menge Code benötigt. Es müssen Request Parameter im Path oder Body auf Richtigkeit validiert werden. Oder Url Mapping Algorithmen mit Request und Response Handlerlogiken ausgestattet werden. Und damit der Benutzer des REST Servers nicht verzweifelt sollte die REST API gut dokumentiert sein. All diese Aufgaben und noch viele mehr kann der OpenApi Ansatz lösen.&lt;/p&gt;
&lt;p&gt;Mit tollen Arbeiten wie dem &lt;a href=&quot;https://github.com/OpenAPITools/openapi-generator-cli&quot;&gt;OpenApi Generator&lt;/a&gt; lassen sich problemlos Rest Server generieren und mittels Swagger HTML UI dokumentieren. Auch kann der REST Server dann problemlos getestet werden zum einen direkt in der Swagger HTML UI mit der try out Funktion und zum anderen können direkt Postman Tests aus dem OpenApi Spec File generiert werden. Die Arbeit mit OpenApi spec is sehr spannen für mich und ich hoffe, ich konnte euch animieren auch mal OpenApi Technologien auszuprobieren. Lasst mich hören wie es bei euch lief!&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 trifft Let's Encrypt]]></title><description><![CDATA[Hi Alfrescans. Während des Alfresco Hackathons im Mai 2020 habe ich für den Docker Alfresco Installer eine Docker Companion Erweiterung…]]></description><link>https://martinmueller.dev/alf-lets-encrypt/</link><guid isPermaLink="false">https://martinmueller.dev/alf-lets-encrypt/</guid><category><![CDATA[de]]></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;Während des Alfresco Hackathons im Mai 2020 habe ich für den &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Docker Alfresco Installer&lt;/a&gt; eine Docker Companion Erweiterung implementiert, um SSL Zertifikate zu verwalten. Diese können dann für eine HTTPS Verbindung genutzt werden. Die SSL Zertifikate werden dabei von &lt;a href=&quot;https://letsencrypt.org/de/&quot;&gt;Let&apos;s Encrypt&lt;/a&gt; ausgestellt und regelmäßig erneuert. Let&apos;s Encrypt dient dabei auch als Autorisierer der Zertifikate. Ziemlich cool oder? Somit muss ich mir weniger Gedanken machen über eine sichere, verschlüsselte und maintainte Verbindung zu meinem Alfresco Proxy.&lt;/p&gt;
&lt;p&gt;Leider wurde der Pull Request abgelehnt, weil der Docker Alfresco Installer im Fokus Demo und Trial bleiben soll. Um aber dieses tolle Feature euch nicht vor zu enthalten sowie einfacher zugänglich zu machen, habe ich mich entschlossen es in meinem GitHub Repo zu implementieren und es euch hier zu präsentieren. Zusätzlich habe ich automatisierte Tests geschrieben welche die noch recht neue Build Engine GitHub Actions nutzen, um das Let&apos;s Encrypt Docker Companion zu testen. In den nächsten Abschnitten erkläre ich die Erweiterung sowie die die automatisierten Tests.&lt;/p&gt;
&lt;h1&gt;Docker Companion&lt;/h1&gt;
&lt;p&gt;Der Code für die Let&apos;s Encrypt Erweiterung ist bei &lt;a href=&quot;https://github.com/mmuller88/alf-lets-encrypt&quot;&gt;mir auf GitHub&lt;/a&gt;. Das Docker Compose Deployment wird mit dem Script ./start.sh gestarted. Soll nun ein SSL Zertifikat von Lets Encrypt ausgestellt werden, benötigst du einen Server auf dem das Docker Compose Deployment ausgeführt wird und eine Domaine die auf diesen Server umleitet. Ich selber habe dafür EC2 VM von AWS genommen und dann einach einen CNAME Record erstellt welche von meiner Domain auf den Public DNS Name von der EC2 VM zeigen. Der CNAME Record sieht dan in etwas so aus:&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;Das Alfresco Docker Compose Deployment kann dann folgendermaßen gestarted werden:&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;Somit wird das gesamte ACS Docker Compose Deployment spezifisch auf https und der Domain a.notreal.net umgestellt. Das Docker Compose Deployment könnte auch ohne die Nutzung des ./start.sh Scripts gestartet werden. Allerding müssten dann die Variablen im Docker Compose File richtig gesetzt werden!&lt;/p&gt;
&lt;p&gt;Die SSL spezifischen Anpassungen im Docker Compose File umfassen dabei nur die drei nochfolgenden 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&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;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;Der erste Service mit namen &lt;strong&gt;proxy&lt;/strong&gt; ist der Alfresco Proxy über welchen die Alfresco Applikationen wie Share oder Alfresco Content App erreichbar sind. Die beiden nachfolgenden Services bilden zusammen die Docker Companion Images für die SSL Zertifikateverwaltung mit Let&apos;s Encrypt.&lt;/p&gt;
&lt;h1&gt;Testing&lt;/h1&gt;
&lt;p&gt;Ich hatte große Lust mal die neue Buildengine GitHub Actions auszuprobieren um die Ausstellung des SSL Zertifkates für die Domain a.notreal.com zu testen. Ich habe mir gedacht es müsste doch möglich sein die GitHub Action Runner nicht von GitHub selber laufen zu lassen, sondern auf AWS direkt. So könnte ich dann einach mittels des CNAME Records auf den Public DNS Name vom AWS Runner verweisen. Und ja das hat tatsächlich geklappt. Viel geholfen hat mir &lt;a href=&quot;https://www.lotharschulz.info/2019/12/09/github-action-self-hosted-runners-on-aws-incl-spot-instances/&quot;&gt;dieser Blog Post von Lothar Schulz&lt;/a&gt; wo genau beschrieben wird, wie ich AWS Ec2 VMs als GitHub Actions Runner verwenden kann. Mein GitHub Workflow sieht folgendermaßen aus:&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;Im Workflow File von GitHub Actions sehen wir das Alfresco gestarted wird mit der Domaine die über den CNAME Record auf den EC2 Runner zeigt. Durch die Ausführung von &lt;code&gt;start.sh&lt;/code&gt; wird Alfresco gestarted und am Schluss die Erreichbarkeit geprüft. Jetzt sollten wir nur noch sicherstellen, dass auch die Indexengine Solr funktioniert. Mittels Newman, welches ein CLI Tool von Postman ist, wird ein Request mit anschließender Validierung als Test benutzt:&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;Dieses tested die Erreichbarkeit von Solr. Zum jetzigen Zeitpunkt sehe ich wenig Sinn in mehr Request Tests mit Postman. Es wäre aber kein Problem dieses zu einem späteren Zeitpunkt nachzuholen. Interessierst du dich mehr für die Möglichkeiten mit Postman? Vor einiger Zeit habe ich schon einen interessanten Artikel geschreiben bei dem ich auch &lt;a href=&quot;https://martinmueller.dev/cdk-example&quot;&gt;Postman verwende&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Verschlüsselte Verbindungen zum Alfresco Proxy sind essenziell für eine Produktionsumgebung mit Alfresco. Es benötigt einen hohen manuellen Aufwand die dafür benötigten SSL Zertifikate zu erstellen, autorisieren und regelmäßig zu erneuern. Mit dem tollen und kostenlosem Angebot von &lt;a href=&quot;https://letsencrypt.org/de/&quot;&gt;Let&apos;s Encrypt&lt;/a&gt; lässt sich dieser Aufwand auf fast null reduzieren. Wenn ihr Kubernetes auch so spannend findet wie ich, könnte man darüber nachdenken kleine Let&apos;s Encrypt Charts zu erstellen, welche in einem Kubernetes Deployment verwendet werden können, um SSL Zertifikate Verwaltung auch in einem Cluster zu erreichen.&lt;/p&gt;
&lt;p&gt;Falls ihr Let&apos;s Encrypt auch für eine Produktionsumgebung nutzt, bitte denkt darüber nach eine Spende and Let&apos;s Encrypt zu entrichten. Somit kann garantiert werden, dass dieser Service auch in Zukunft kostenlos bleibt. Ich bedanke mich für eure Aufmerksamkeit und hoffe auf reichliches Feedback :).&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Der Alfresco Provisioner]]></title><description><![CDATA[Hi Alfrescans. Hast du schonmal Alfresco auf einer AWS Ec2 Instanz installiert? Vielleicht sogar auch schon mit Docker Compose? Auch wenn…]]></description><link>https://martinmueller.dev/alf-provisioner/</link><guid isPermaLink="false">https://martinmueller.dev/alf-provisioner/</guid><category><![CDATA[de]]></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><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;Hast du schonmal Alfresco auf einer AWS Ec2 Instanz installiert? Vielleicht sogar auch schon mit Docker Compose? Auch wenn Docker die Installation von Alfresco einfacher gemacht hat, ist es immer noch aufwending! Zuerst muss man eine Ec2 Instanz erstellen. Dafür muss man sich in AWS einloggen, einen Ec2 Typen auswählen und diesen starten. Dann dort drauf connecten, Docker installieren und dann muss noch eine Alfresco Docker Compose Installation durchführen. Wie toll wäre es wenn wir einfach einen Managed Service hätten welche das für uns macht?&lt;/p&gt;
&lt;p&gt;Gute Nachrichten! Genau das habe ich in den letzten Wochen implementiert. Es muss nun einfach nur noch der gewünschte Ec2 Typ und das gewünschte Alfresco Docker Compose Deployment auswählen und der Alfresco Provisioner übernimmt den Rest und installiert Alfresco für dich! Damit kann Jeder schnell und einfach Alfresco Backends für sich und seine Community erstellen. In den nächsten Abschnitten werde ich genauer von meiner Idee berichten sowie welche Technologien ich dafür verwendet habe.&lt;/p&gt;
&lt;h1&gt;Zielgruppe&lt;/h1&gt;
&lt;p&gt;Für die Alfresco Produkte sehe ich auch einen klaren Bedarf bei den eher kleineren Gruppen. Ich habe sogar ein gutes Beispiel aus meiner näheren Umgebung. Ich bin Mitglied in einer Kirchgemeinde. Nun würde sich die Kirchgemeinde gerne modernisieren, auch hin in Richtung Digitalisierung. So werden zum Beispiel Videos von Gottesdiensten auf Youtube hochgeladen oder gemachte Bilder landen irgendwo in Dropbox. Auch werden Gemeinschaftsprojekte hauptsächlich nur auf Stift und Papier geplant, da die richtigen digitalen Werkzeuge einfach fehlen. Ich sehe die Alfresco Produkte in der Lage einer Gruppe wie meiner Kirchengemeinde damit zu helfen, effizienter digitalen Content zu verwalten. Mit großer Wahrscheinlichkeit kennst auch auch du Gruppierungen wie zum Beispiel Vereine in deiner Umgebung die von Alfresco profitieren könnten.&lt;/p&gt;
&lt;p&gt;Auch könnte das schnelle bereitstellten von Alfresco Backends Communities bei der zwingend erforderlichen Digitalisierung wärend der Coronakrise helfen. Es sollte so gut es geht vermieden werden Dokumente in Echt von Person zu Person auszutauschen oder daran gemeinschaftlich von Angesicht zu Angesicht daran zu arbeiten. Gerne würde ich meinen Beitrag leisten bei der Pandemie zu helfen und vielleicht ist der Alfresco Provisioner ja eine Möglichkeit.&lt;/p&gt;
&lt;p&gt;Herausfordernd wird dan natürlich die verursachten Kosten so gering wie möglich zu halten und die Kostenvorteile der Cloud so gut es geht an den Nutzer weiter zu leiten. Ein paar Ideen die ich diesbezüglich bereits habe sind die Verwendung von Reserved Instances, Spot Instances, S3 als Objektspeicher, Pay as you go für die Alfresco Instanzen und die Möglichkeit die eigenen Ec2 Instanzen nutzen zu können.&lt;/p&gt;
&lt;p&gt;Eine andere Möglichkeit bestünde darin, die mit Docker Compose erzeugen und einfach erweiterbaren Backends für Demozwecke zu verwenden und somit potentiellen Nutzer zu zeigen, zu was Alfresco Produkte alles in der Lage sind.&lt;/p&gt;
&lt;h1&gt;Verwendete Technologien&lt;/h1&gt;
&lt;p&gt;Der Alfresco Provisioner verwendet eine Vielzahl moderner Technologien. Ich beschreibe diese nachfolgend in den Kategorien Backend, Frontend und 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;Die Alfresco Instanzen werden mit Hilfe von Docker Compose, welche ich mit dem &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt; erstellt habe, betrieben. Diese laufen dann auf AWS Ec2 Instanzen. Die Verwendung von Ec2 Instanzen für ein Alfresco Backend ist mittlerweile sehr verbreitet. Allerding mache ich diese Kreierung der Instanzen so dynamisch und flexible wie nur möglich. Ich habe nämlich ein AWS Api GateWay erstellt welches autonom in der Lage ist mittels API Requests vom Nutzer, dies Ec2 Instanzen zu starten, stoppen und terminieren.&lt;/p&gt;
&lt;p&gt;Nachdem die Instanz gestartet ist, erhält der Nutzer eine Url die ihm zum Alfresco Backend bringt. Hinter dem Api Gateway arbeiten außerdem noch eine vielzahl an Lambdas, Step Functions, Dynamo DB Tables und S3 Buckets um diese zu ermöglichen. All das ist mit Infrastruktur als Code in AWS CDK verfasst. Als Programmiersprache für CDK und den Lambdas verwende ich TypeScript. TypeScript habe ich wärend dieses Projekts lieben gelernt und es ermöglicht mir ein sehr schnelles Entwickeln des Alfresco Provisioner. Auch wird mittels CDK ein Swagger File erzeugt, welches als UI und Client Library für das Frontend gilt. Nähere wie man Swagger / OpenApi lückenlos in CDK einbindet habe ich &lt;a href=&quot;https://martinmueller.dev/cdk-swagger&quot;&gt;in diesem Beitrag beschrieben&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;Das Frontend ist, verglichen mit dem Backend, noch sehr bescheiden. Das liegt zu einem daran das ich noch viel zu lernen habe im Frontendbereich aber auch daran, dass sich das Backend schnell weiterentwickelt und ich nicht jedesmal UI Components neu anpassen möchte. Meine Wahl der Technologien sind React und TypeScript. React besticht durch eine reiche Auswahl an schönen Components und TypeScript ist eine geniale Sprache. Um TypeScript kurz zu beschreiben es nimmt aus Java und JavaScript nur das Beste. Am besten finde ich die Möglichkeit Types zu verwenden. Das dient als Dokumentation und ich schaffe Ordnung im eher Typlosen Dschungel von JavaScript. Auch ist das Nullhandling bzw. Undefinedhandling von TypeScript super.&lt;/p&gt;
&lt;p&gt;Darüber hinaus habe ich mich entschlossen den OpenAPI UI Explorer als meine UI zu verwenden. Das hat einfach den super Vorteil, dass quasi die UI Components nur aufgrund des Swagger Files gerendert werden und ich nicht selber Hand anlegen muss. Quasi automatisch generierte Components. Nähere darüber kannst du von meinen vorherigen Posts herausfinden und auf den Swagger UI Seite in &lt;a href=&quot;https://github.com/swagger-api/swagger-ui&quot;&gt;GitHub&lt;/a&gt; und auf &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;Mit DevOps Pipeline meine ich den Prozess vom implementieren neuer Features bis hin zur Production. Diese Wege können sehr vielfältig sein. Es hat sich allgemein aber eingestellt soviel wie möglich automatisieren zu lassen. Bei meiner Pipeline habe ich einen sehr hohen Automatisierungsgrad erreicht. Ich muss quasi nur nach den master Branch pushen, dann wird ein Teststack aufgebaut und danach Postmantests gegen das API GateWay durchgeführt. Wenn die tests erfolgreich waren wird der Produktionsstack geupdated. Dieses Verhalten kann ich noch leicht beeinflussen im Code selber indem ich folgende Variablen setze:&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;
  &lt;span class=&quot;token key atrule&quot;&gt;destroyBefore&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;deploy&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;updateProduction&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;destroyAfter&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Auch nutze ich AWS CDK welches mir erlaubt per TypeScript den Test- und Produktionsstack zu definieren. Näheres darüber kann in meinem vorherigen Post nachgelesen werden &lt;a href=&quot;https://martinmueller.dev/cdk-multistack&quot;&gt;CDK Multistack&lt;/a&gt; oder &lt;a href=&quot;http://martinmueller.dev/cdk-example&quot;&gt;CDK allgemein&lt;/a&gt;. Travis und AWS CDK finde ich eine geniale Kombination&lt;/p&gt;
&lt;h1&gt;Wie Funktionierts?&lt;/h1&gt;
&lt;p&gt;Das Provisioning der Alfresco Instanzen geschieht via REST API. Der Nutzer logt sich dafür auf der Website ein, erhält dann ein OAUTH Token und kann damit dann neue Alfresco Instanzen erstellen, alte abrufen und ändern. Dadurch dass ich den OpanAPI UI Explorer benutze, erhält der Nutzer genauste Informationen wie die API zu bedienen ist, also welche Parameter in den Requests und Response zu setzen bzw. zu erwarten sind.&lt;/p&gt;
&lt;p&gt;Nachfolgend list ich wie zum Beispiel der Body im POST Request ist zum Erstellen einer neuen Instanz:&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;Die &lt;strong&gt;userId&lt;/strong&gt; ist lediglich der Username im System und &lt;strong&gt;customName&lt;/strong&gt; ein Spitzname für das Alfresco Backend kreiert mit dem Provisioner. &lt;strong&gt;AlfType&lt;/strong&gt; beschreibt den Typ des Alfresco Backends. Dieser setzt sich zusammen aus dem Typen den Ec2 VM &lt;strong&gt;ec2InstanceType&lt;/strong&gt; und einem Alfresco Docker Compose Repository &lt;strong&gt;gitRepo&lt;/strong&gt;. Das GitHub Repository ist auf meinem Account und Private. Zurzeit unterstütze ich nur eins:&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;Alle Komponenten wurden installiert mit dem &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt;. Natürlich ist geplant dieses Angebot in Zukunft weit auszubreiten. Es wäre auch denkbar Alfresco Git Repositories von anderen Usern, die nicht aus meinem GitHub Realm stammen, zu nutzen. Sie müssten nur einen gewissen Standard erfüllen und dann spräche nichts dagegen.&lt;/p&gt;
&lt;p&gt;Eine detaillierte Beschreibung aller REST Endpoints sowie dessen Requests und Response Parameter können auf der Alfresco Provisioner UI Seite nachgelesen werden.&lt;/p&gt;
&lt;h1&gt;Geplante Features&lt;/h1&gt;
&lt;p&gt;Bereits jetzt sind viele Features geplant, die es dem Nutzer ermöglichen Geld zu sparen, den Umgang mit den Alfresco Produkten erleichtern und das Backend sicherer zu machen. Der Nutzer soll in der Lage sein die Instanzen stoppen und starten zu können. Wenn die Instanz gestoppt ist, braucht der Nutzer nicht mehr für den Compute zu bezahlen sondern nur noch für den Storage oder evtl. garnicht mehr. Auch nützlich wäre eine Erweiterung zur automatischen Erstellung von Backups. Dafür werde ich mir die interessante Arbeit von Tony mit &lt;a href=&quot;https://github.com/toniblyx/alfresco-backup-and-recovery-tool&quot;&gt;Alfresco BART&lt;/a&gt;. Das würde es auch ermöglichen einfacher zu anderen alfTypes upzugraden. Zum jetzigen Zeitpunkt habe ich damit schon einen guten Fortschritt gemacht indem ich ein Tool in Go geschrieben habe, welches backups erstellen kann. Jetzt fehlt nur noch die Möglichkeit diese auch wieder in Alfresco einspielen zu können.&lt;/p&gt;
&lt;p&gt;Bisher ist noch kein HTTPS zum Proxy der Instanzen eingerichtet. Ich plane dafür die Zertifikate bereitgestellt von Let&apos;s Encrypt zu nutzen. Dafür muss man einfach ein Docker Companion erstellen, welcher die Zertifikate Verwaltung übernimmt. Auch sollte es so möglich sein die Zertifikate automatisch vor Ablauf erneuern zu lassen. Bisher ist nur ACS Community eingerichtet aber ich plan auch andere Produkte von Alfresco wie ACS Enterprise oder APS anzubieten. Auch denke ich über einen Onboarding Layer für ACA nach.&lt;/p&gt;
&lt;p&gt;Ein weiteres nützliches Feature wäre es, wenn der Nutzer die Instanz Url einfach umleiten kann zu seiner eigenen Domain Url.&lt;/p&gt;
&lt;h1&gt;Closed Alpha&lt;/h1&gt;
&lt;p&gt;Ich werde bald den Alfresco Provisioner der Öffentlichkeit zu Verfügung stellen. Dafür habe ich mir gedacht eventuell erstmal eine Closed Alpha zu veranstalten. So können Interessierte den Alfresco Instanz Provisioner ausprobieren, Feedback geben und mehr.&lt;/p&gt;
&lt;p&gt;Bei Interesse schreibt mir und ich erstelle dann euren Zugangsaccounts. Alles was ich brauche ist die Email Adresse und der gewünschte User Name. Ich habe noch keinen genauen Starttermin für die Closed Alpha allerdings bin ich zuversichtlich, dass ich es noch im Mai passieren wird.&lt;/p&gt;
&lt;h2 id=&quot;kurze-anleitung-über-die-benutzung-des-alfresco-provisioner&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#kurze-anleitung-%C3%BCber-die-benutzung-des-alfresco-provisioner&quot; aria-label=&quot;kurze anleitung über die benutzung des 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;Kurze Anleitung über die Benutzung des Alfresco Provisioner&lt;/h2&gt;
&lt;p&gt;Ich habe mich dazu entschlossen ein kurzes Video darüber zu machen, wie der Alfresco Provisioner benutzt werden kann. Das Video kann hier angeschaut werden: &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;mehr-über-die-alfresco-produkte&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#mehr-%C3%BCber-die-alfresco-produkte&quot; aria-label=&quot;mehr über die alfresco produkte permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Mehr über die Alfresco Produkte&lt;/h2&gt;
&lt;p&gt;Wenn du mehr über die in der Closed Alpha genutzten Alfresco Produkte wissen möchtest, habe ich mir gedacht hier ein paar Informationen darüber bereitzustellen. Der Alfresco Provisioner installiert
die moderne &lt;a href=&quot;https://github.com/Alfresco/alfresco-content-app&quot;&gt;Alfresco Angular WebApp ACA&lt;/a&gt; welches als vereinfachte und Dateispezifische Version von Share angesehen werden kann. ACA wird sitzt auf Root. Es muss also nur die URL der Instanz eingegeben werden z.B. &lt;a href=&quot;http://ec2-1-2-3-4.eu-west-2.compute.amazonaws.com/&quot;&gt;http://ec2-1-2-3-4.eu-west-2.compute.amazonaws.com/&lt;/a&gt; Eine schnelle Runde über die Fähigkeiten von ACA wird &lt;a href=&quot;https://docs.alfresco.com/adw1.0/concepts/welcome-adw.html&quot;&gt;hier&lt;/a&gt; gezeigt.&lt;/p&gt;
&lt;p&gt;Share welches mit /share aufgerufen werden kann bietet zusätzlich zu ACA eine riesige Auswahl von Funktionen. Einen groben Überblick können die nachfolgenden Video verschaffen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=YhtMv86LP10&quot;&gt;https://www.youtube.com/watch?v=YhtMv86LP10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ZWz1wXq7zCk&quot;&gt;https://www.youtube.com/watch?v=ZWz1wXq7zCk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=8R1FCoWm0xY&quot;&gt;https://www.youtube.com/watch?v=8R1FCoWm0xY&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Aus Persönlicher Sicht&lt;/h1&gt;
&lt;p&gt;Was mir am meisten gefällt an diesem Projekt ist einfach mal die Tatsache, dass der Großteil der Implementierung, Testung, Entwicklung und Dokumentierung mit Hilfe der Swagger Definition geschieht. Das geht hin von der Validierung der Request Parameter, Implementierung der REST Schnittstelle, Dokumentation, Visualisierung mit Swagger UI und automatisierten Tests in Postman. Ich liebe den Ansatz mit der Swagger Definition, die ich per Swagger Plugin im Visual Studio Code previewen kann, für fast alles nutzen zu können. Aus meinser Sicher ist das die Zukunft der Serverimplementierung.&lt;/p&gt;
&lt;p&gt;Das Weiteren bin ich einfach immer noch Überwältigt mit was ein einziger Entwickler in der Lage ist mit AWS CDK, ins Besondere im TypeScript Flavor, zu tun. Meine Begeisterung zu &lt;a href=&quot;http://martinmueller.dev/cdk-example&quot;&gt;CDK&lt;/a&gt; habe ich bereits hier beschrieben und möchte es hier nicht wieder holen. Bitte nachholen.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Was als einfaches AWS CDK experiment startetet entwickelte sich rasch zu einem tollen neuen Service den ich den Alfresco Provisioner genannt habe. Damit ist es einfach möglich Alfresco Backends, welche mit Docker Compose entwickelt wurden, bereitzustellen. In der Closed Alpha Phase lade ich dich herzlich ein den Service zu nutzen.&lt;/p&gt;
&lt;h1&gt;Kudos&lt;/h1&gt;
&lt;p&gt;Ein fettes Dankeschön an die &lt;a href=&quot;https://gitter.im/awslabs/aws-cdk&quot;&gt;AWS CDK Community in Gitter&lt;/a&gt;. Selten habe ich eine Community so sehr in Liebe verfallen zu der Technologie gesehen.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 Mai 2020 Zusammenfassung]]></title><description><![CDATA[Hi Alfhackas. Der Alfresco Hack-a-thon war super. Am meisten gefallen haben mir die persönlichen Gespräche mit vielen tollen Exkollegn sowie…]]></description><link>https://martinmueller.dev/alf-hackathon-danach/</link><guid isPermaLink="false">https://martinmueller.dev/alf-hackathon-danach/</guid><category><![CDATA[de]]></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;Der Alfresco Hack-a-thon war super. Am meisten gefallen haben mir die persönlichen Gespräche mit vielen tollen Exkollegn sowie anderen Alfrescojüngern. Darüber hinaus konnte ich auch wertvollen Informationen über Geplante Projekte innerhalb von Alfresco erfahren. Zum Beispiel bin ich sehr gespannt wohin sich Digital Workspace, die hübsche Angular Webapp für ACS Enterprise, entwickelt. Sehr bald wird es UI Elemente bekommen um APS Elemente wie Task und Prozesse anzeigen zu können. Ich wurde auch darauf hingewiesen, dass ich als Alfresco Partner Zugriff zu dem Digital Workspace Repository bekommen könnte, was ich definitiv dankbar machen werde.&lt;/p&gt;
&lt;h1&gt;Lets Encrypt&lt;/h1&gt;
&lt;p&gt;Mein Projekt für den Hack-a-thon war es dem &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Docker Alfresco Installer&lt;/a&gt; eine Docker Erweiterung zu spendieren, welche es ermöglichen würde Lets Encrypt autorisierte Zertifikate für die HTTPS Verbindung zu nutzen. Sogar würde die Erweiterung den kompletten Lifecycle des Zertifikates managen. Ich bin zwar nicht komplett fertig geworden damit aber konnte ein gutes Stück implementieren und dieses Wochenende werde ich garantiert damit fertig.&lt;/p&gt;
&lt;h1&gt;Zum Abschluss&lt;/h1&gt;
&lt;p&gt;Vielen lieben Dank an die Organisierer des Alfresco Hack-a-thon und an die die tolle Alfresco Community. Definitiv bin ich wieder dabei beim nächsten Hack-a-thon. Cheers.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 Mai 2020]]></title><description><![CDATA[Hi Alfrescans. Am 11 Mai 2020 veranstaltet Alfresco ein virtuelles Hackathon. Die aktuellen Projektideen findet ihr hier auf hub.alfresco…]]></description><link>https://martinmueller.dev/alf-hackathon/</link><guid isPermaLink="false">https://martinmueller.dev/alf-hackathon/</guid><category><![CDATA[de]]></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;Am 11 Mai 2020 veranstaltet Alfresco ein virtuelles Hackathon. Die aktuellen Projektideen findet ihr hier auf &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;. Mit diesem Post will ich euch recht herzlich einladen teilzunehmen.&lt;/p&gt;
&lt;h1&gt;Warum Teilnehmen?&lt;/h1&gt;
&lt;p&gt;Es kann verschiedene Gründe haben warum du teilnehmen solltest. Wenn du die Alfresco Produkte magst, ist es toll mitzuhelfen die Produkte weiter zu entwickeln oder gar komplett neue zu erschaffen. Ich zum Beispiel hätte gerne einen SSL Companion Container für den &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt;. Kurzerhand habe ich das Projekt einfach angemeldet um mitzuhelfen es zu organisieren und durchzuführen.&lt;/p&gt;
&lt;p&gt;Auch ist eine tolle Gelegenheit Kontakte mit motivierten Entwicklern aus aller Welt zu knüpfen. Wärend meiner Zeit bei Alfresco habe ich schlaue als auch hilfsbereite Entwickler kennengelernt, von denen ich mir viel abgeschaut habe. Ich suche immer nach Gelegenheiten zu lernen und der Hackathon ist die perfekte Gelegenheit dafür.&lt;/p&gt;
&lt;p&gt;Auch unsere Firma von Object würde gerne mal in Zukunft einen Hackathon veranstalten und der Alfresco Hackathon könnte eine perfekte Gelegenheit seit zu lernen wie man solche Hackathons veranstalten kann.&lt;/p&gt;
&lt;p&gt;Der beste Grund: Why not? Es könnte eine interessante neue Erfahrung für dich sein und wenn es dir nicht gefällt, kannst du jeder Zeit gehen und beim nächsten mal einfach nicht mitmachen.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Der Alfresco Hackathon am 11 Mai 2020 steht vor der Tür. In die Startlöcher meine Freunde :) ! Nach dem Even werde ich in Form eine Posts hier berichten wie mie der Hackathon gefallen hat. Bis zum 11 dann und bleibt gesund :D !&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Go Alfresco BART]]></title><description><![CDATA[UNDER CONSTRUCTION
Hi Alfrescans. Backups von ACS zu machen und auch diese gegebenfalls wieder einzuspielen war noch nie leicht bei Alfresco…]]></description><link>https://martinmueller.dev/alf-go-bart/</link><guid isPermaLink="false">https://martinmueller.dev/alf-go-bart/</guid><category><![CDATA[de]]></category><category><![CDATA[2020]]></category><category><![CDATA[acs]]></category><category><![CDATA[backup]]></category><category><![CDATA[docker]]></category><category><![CDATA[docker-compose]]></category><category><![CDATA[travis]]></category><pubDate>Sun, 03 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;UNDER CONSTRUCTION&lt;/strong&gt;
Hi Alfrescans.&lt;/p&gt;
&lt;p&gt;Backups von ACS zu machen und auch diese gegebenfalls wieder einzuspielen war noch nie leicht bei Alfresco. Eine genau Anleitung wie es gemacht werden sollte findet ihr in &lt;a href=&quot;https://docs.alfresco.com/6.2/concepts/backup-intro.html&quot;&gt;Alfresco&apos;s Dokumentation&lt;/a&gt;. Da liegt es natürlich nahe, dass man sich ein gewisses Tooling wünscht, welches diesen Aufwand stark reduziert. Vor einigen Jahren hat Tony ein bemerkenswertes Tool den &lt;a href=&quot;https://github.com/toniblyx/alfresco-backup-and-recovery-tool&quot;&gt;Alfresco BART&lt;/a&gt; geschrieben. Das Projekt wurde aber leider nicht weiter entwickelt. Nun habe ich die Idee eine komplett neue Version mit mehr Features zu schreiben welches ich Go Alfresco BART nenne.&lt;/p&gt;
&lt;h1&gt;Motivation&lt;/h1&gt;
&lt;p&gt;Das existierende BART besitzt eine hohe Komplexität und ist mit sicherheit nicht mehr Kompatibel mit Alfresco. Ich muss aber ehrlich gestehen, dass ich BART nicht getested habe. Wie auch immer. Zusätzlich bin ich daran interessiert die Sprache Go zu lernen. Schon nach meinem ersten kleinen Go Projekt ist mir klar, das Go perfekt wäre für eine neue Version von Alfresco BART. Mit diesem Projekt implementiere ich als eine neue, verbesserte Version von BART und lerne Go besser kennen.&lt;/p&gt;
&lt;h1&gt;Verwendete Technologien&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Go Lang&lt;/li&gt;
&lt;li&gt;Travis&lt;/li&gt;
&lt;li&gt;Repo &lt;a href=&quot;https://github.com/huacnlee/gobackup&quot;&gt;https://github.com/huacnlee/gobackup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;Bei Interesse schreibt mir und ich erstelle dann euren Zugangsaccounts. Alles was ich brauche ist die Email Adresse und der gewünschte User Name. Ich habe noch keinen genauen Starttermin für die Closed Alpha allerdings bin ich zuversichtlich, dass ich es noch im Mai passieren wird.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 Multistacks für Test und Produktion]]></title><description><![CDATA[Hi AWS Fans, Wie gut sich AWS CDK zur Beschreibung in Code der Infrastruktur eignet habe ich ja bereits in einem vorherigen Beitrag…]]></description><link>https://martinmueller.dev/cdk-multistack/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-multistack/</guid><category><![CDATA[de]]></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>Sat, 18 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;Wie gut sich AWS CDK zur Beschreibung in Code der Infrastruktur eignet habe ich ja bereits in einem &lt;a href=&quot;https://martinmueller.dev/cdk-example&quot;&gt;vorherigen Beitrag&lt;/a&gt; beschrieben. In diesem Beitrag soll es darum gehen wie CDK in einer Test- und Produktionsumgebung aussehen könnte. In meinem privaten Projekt habe ich bereits so etwas wie eine Produktionsumgebung implementiert und bin sehr begeistert davon. Kurz gesagt dafür benutze ich 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 den nächsten Abschnitten beschreibe ich wie mein Deployment aussieht.&lt;/p&gt;
&lt;h1&gt;CDK Multistack&lt;/h1&gt;
&lt;p&gt;Ein CDK Multistack ist ein CDK Deployment welches mehrere Stacks verwaltet. Diese Stacks können in der gleichen oder anderen Regionen sein oder sogar in einem anderen AWS Accounts. Die unterschiedlichen Stacks können dann einfach bei der Erstellung mit verschiedenen Parameter initialisiert werden. Nachfolgend ist ein Beispiel mit zwei 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;Das ist ein kleiner Ausschnitt aus meinem Projekt. Der erste Stack mit Namen EuWest2Prod beschreibt den Produktionsstack der sogar in einem anderen Account liegt. Der Zweite Stack EuWest2 ist der Teststack. Diese Art und Weise der Parametrisierung lässt sich hervorragend nutzen um Features an und auszuschalten. Im Produktionsstack habe ich mit der Auskommentierung von createInstances das Feature zur Erstellung von Ec2 Instanzen erstmal ausgestellt um Kosten zu sparen. Auch unterstützt die Parametrisierung eine einfach Migration von einem AWS Account zu einem anderen.&lt;/p&gt;
&lt;p&gt;In den nächsten Abschnitten will ich mehr über meinen Teststack und Produktionsstack für mein Projekt sprechen. Mann muss aber fairerweise erwähnen, dass ich noch keine wirkliche Produktion habe. Also sprich echte Kunden, die meinen Service nutzen. Ich hoffe dieses natürlich bald ändern zu können. Zum jetzigen Zeitpunkt versuche ich Erfahrungen zu sammeln wie ich eine echte Produktion möglichst gut am laufen halten könnte, sprich neue Features problemlos implementieren. Dafür eignen sich AWS ChangeSets für CloudFormationstacks sehr gut. Diese ändern den jeweiligen Stack nur mit den erforderlichen Updates. Bevor du weiterliest, es macht definitiv Sinn über AWS ChangeSets für CloudFormations sich zu informieren.&lt;/p&gt;
&lt;h1&gt;Teststack&lt;/h1&gt;
&lt;p&gt;Teststacks sollten in erster Linie günstig sein. Die Tests werden ausgeführt und das Logresult sollte dem Developer einfach zugänglich sein. Kurz danach sollte der Stack die Ressourcen vernichten. Ist noch eine manuelle Begutachtung des Teststacks erwünscht kann man eine Verzögerung der Vernichtung nach den Tests implementieren. Ich habe das zum Beispiel bei den Ec2 Instanzen gemacht, die sich selber nach 55 Minuten terminieren.&lt;/p&gt;
&lt;p&gt;Und natürlich sollte der Teststack testen. Was das genau ist hängt von deinem Use Case ab. Bei mir teste ich gegen ein API GateWay und dessen Endpoints. Im Hintergrund werden mehrere DynamoDB Tabellen, sowie EC2 Instanzen kreiert oder terminiert mittels Step Functions. Das mache ich mit Postman. Falls dich das Testen mehr interessiert habe ich bereits darüber in meinem &lt;a href=&quot;https://martinmueller.dev/cdk-example&quot;&gt;vorherigen Post&lt;/a&gt; berichtet.&lt;/p&gt;
&lt;p&gt;An sich wars das. Wenn die Testphase erfolgreich war, kann das Update in die Produktions angewandt werden. Das wird im nächsten Abschnitt beschrieben.&lt;/p&gt;
&lt;h1&gt;Produktionsstack&lt;/h1&gt;
&lt;p&gt;Der Produktionsstack ist für die Kunden gedacht. Dort muss als alles bestmöglich funktionieren und neue Features sollten erst implementiert werden, wenn sie sich im Teststack bewiesen haben. Auch kann es Sinn machen den Produktionsstack mit etwas veränderten Service Einstellungen zu betreiben. Ein Beispiel dafür wäre, dass ich im Teststack ja keine wirklich User Verwaltung ggf. mit Cognito brauche, aber im Produktionsstack schon. Somit wird die Komplexität im Teststack geringer gehalten. Im obigen Snippet habe ich Cognito in der Produktion definiert. Ein weiteres Beispiel wären EC2 Instanzen. Im Teststack reichen vielleicht kostengünstige EC2 Typen wohingegen in der Produktion stärkere und somit kostenintensivere Instanzen nötig sind.&lt;/p&gt;
&lt;p&gt;Es stellt sich nun die Frage wo der Produktionsstack deployed werden sollte. Glücklicherweise bietet uns CDK dort jede Freiheit. Es ist möglich den Stack in der gleichen oder in einer anderen Region, im gleichen Account zu deployen. Auch kann der Produktionsstack in einem anderen Account deployed werden. Dafür müssen dann aber Profiles genutzt werden. Hier ist mal ein Beispiel:&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;&lt;span class=&quot;token variable&quot;&gt;$STACK_NAME_PRODUCTION&lt;/span&gt;&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;Dieser Stack wird nun in einem anderen AWS Account deployed. Bisher habe ich mit dieser Art und Weise der Deployments eine gute Erfahrung gesammelt. Ein Nachteil hat diese Art des Deployments allerdings. Da ich nun auf den Profile parameter angewiesen bin, kann ich den gleichen cdk deploy Befehl nicht auch für den Teststack nutzen und ich muss zwei CDK Befehle ausführen:&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;&lt;span class=&quot;token variable&quot;&gt;$STACK_NAME_TEST&lt;/span&gt;&quot;&lt;/span&gt;
cdk deploy &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$STACK_NAME_PRODUCTION&lt;/span&gt;&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;Es wäre toll wenn ich bei der Definition im Multistack einfach den Profil namen angeben könnte. Wirklich schlimm ist dieser Nachteil natürlich nicht, da in einer vernünftigen Pipeline sowieso der Teststack alleine nur ausgeführt werden sollte und nachdem die Testphase abgeschlossen ist der Produktionstack deployed wird.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt; Ich habe Feedback bekommen, dass es dafür bereits einen Workaround gibt in der 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;Travis sollte jedem Developer bekannt sein. Der Free Tier von Travis erlaubt es, wenn dein GitHub Projekt public ist, darfst du VMs von Travis benutzen. Diese müssen dann lediglich nur noch in der .travis File definiert und konfiguriert werden. Genau das mache ich. Ehrlich gesagt nutze ich Travis sehr stark. Ich beschreibe einfach mal kurz meinen Workflow wenn ich ein neues Feature kreiere:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Code Anpassungen von neue Feature in master schreiben.&lt;/li&gt;
&lt;li&gt;Ggf. neuen Test in Postman hinzufügen.&lt;/li&gt;
&lt;li&gt;master committen --&gt; Travis build wird getriggert.&lt;/li&gt;
&lt;li&gt;Travis schlägt fehl oder passt.&lt;/li&gt;
&lt;li&gt;Wenn es fehl geschlagen ist, reverted der Stack automatisch und ich werte die Logs aus um zu sehen was schief lief. Zurück zu schritt 1).&lt;/li&gt;
&lt;li&gt;Wenn es passt ist auf allen Stacks das neue Feature und ich kann es jetzt manuell testen.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Das ist sehr genial da ich weniger Interaktionen ausführen muss um dieses neue Feature zu implementieren. Der gesamt Build dauert in etwa 10 Minuten und ich kann dann 10 Minuten einfach was anderes machen. Diese Art der Pipeline hat mir ein sehr schnelle Iteration von neuen Features gebracht. Ich bin regelrecht baff was heutzutage möglich ist mir nur einem DevOps. Was ich alleine leisten kann, dafür hätte man vor 5 Jahren garantiert etwa 10 Leute anstatt nur einem gebraucht.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;CDK&apos;s Multistacks sind eine tolle Art und Weise mehrere Stacks wie einen Teststack und Produktionsstack zu verwalten. Für mein kleines Projekt habe ich tolle Erfahrungen mit dieser Art der Stackverwaltung gesammelt und hier beschrieben. Bisher hat auch komplett ein relative kleiner Travis build ausgereicht um eine nützliche Pipeline zu kreieren. Ich erwäge in AWS CodePipeline reinzuschauen ob es mir Vorteile bieten könnte. Ich hoffte euch hat meine kleine Zusammenfassung gefallen :)&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 und APS Deployment mit Docker Compose]]></title><description><![CDATA[Hi Alfrescans. Es ist mal wieder Zeit über ein spannendes Alfresco Partner Projekt von mir zu berichten. Für einen Kunden hier in…]]></description><link>https://martinmueller.dev/alf-acs-aps/</link><guid isPermaLink="false">https://martinmueller.dev/alf-acs-aps/</guid><category><![CDATA[de]]></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>Sat, 11 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;Es ist mal wieder Zeit über ein spannendes Alfresco Partner Projekt von mir zu berichten. Für einen Kunden hier in Deutschland entwickle ich ein POC welches ACS 6.2 und APS 1.10 verwenden soll. Nach ein wenig Überzeugungsarbeit konnte ich die Beteiligten davon überzeugen, Docker für ACS 6.2 zu verwenden. Mein Plan war es ein Docker Compose Deployment zu erstellen welche ACS, APS und als Identity Provider openLDAP beinhaltet. Das komplette Deployment kann &lt;a href=&quot;https://github.com/mmuller88/alf-acs-aps&quot;&gt;bei mir in GitHub&lt;/a&gt; gesichtet werden. Eines sei vorweg noch erwähnt. Alfresco offiziell empfiehlt für solche Deployments doch bitte &lt;a href=&quot;https://github.com/Alfresco/alfresco-dbp-deployment&quot;&gt;Kubernetes zu verwenden&lt;/a&gt;, allerdings ist für meinen Kunden die Cloud erstmal noch ein Tabuthema. Darüber hinaus bin ich gespannt zu sehen wie weit ich mit Docker Compose für so ein Deployment kommen werde.&lt;/p&gt;
&lt;h1&gt;Docker Compose Setup&lt;/h1&gt;
&lt;p&gt;Hier beschreibe ich etwas mehr im Detail welche Technologien ich für das Deployment benutze. Wie Eingangs angedeuted soll ACS 6.2 installiert werden. Die zum jetzigen Zeitpunkt zuletzt releaste Version ist 6.2.0.3. Das muss also nur im alfresco Dockerfile in /alfresco/Dockerfile reflektiert werden. Share bleibt auf Version 6.2.0 da keine neuere Version released wurde. ACS soll mit einer openLDAP DB zur User Provisioning connected werden. Zum Glück gibt es bereits toll ausgearbeitete Images zur Erstellung und Management einer &lt;a href=&quot;https://github.com/osixia/docker-openldap&quot;&gt;openLDAP DB&lt;/a&gt;. Zur optischen Verwaltung der openLDAP DB benutze ich &lt;a href=&quot;http://phpldapadmin.sourceforge.net/wiki/index.php/Main_Page&quot;&gt;phpldapadmin&lt;/a&gt;. Wie genau die openLDAP Konfigurations aussieht einfach im docker-compose-base.yml File nachlesen.&lt;/p&gt;
&lt;p&gt;Auch soll &lt;a href=&quot;https://docs.alfresco.com/process-services1.10/concepts/welcome.html&quot;&gt;APS 1.10&lt;/a&gt; zur Modellierung der Workflows beim Kunden verwendet werden. Etwas ungünstig ist die Tatsache, dass Alfresco keine Docker Compose Referenz Deployments für APS 1.10 mehr anbietet. Ich vermute mal, dass ist aufgrund des Kubernetes Deployments und das einfach darauf ein stärker Fokus gelegt wird. Zum Glück existieren noch ein paar alter &lt;a href=&quot;https://github.com/AlfrescoLabs/aps-docker-library/tree/master/docker-compose&quot;&gt;Docker Compose Vorlagen&lt;/a&gt; und mit ein paar Modifikationen funktionieren diese auch!&lt;/p&gt;
&lt;p&gt;Da es sehr Memoryintensiv ist ACS und APS gleichzeitig zu laufen, habe ich mich entschlossen das komplexe Deployment in drei voneinander separierbare Deployments zu teilen. Somit kann ich auch weiterhin auf meinem 16 GB Memory Laptop effizient arbeiten. Die Teilung geschieht mittels Docker Compose Files. Das Erste ist das ACS Deployment, gefolge vom Zweiten mit dem APS Deployment. Zu guter Letzt gibt es dann noch das ACS und APS Deployment. Ich finde das eine geniale Idee da ich nun, falls ich nur an ACS oder APS arbeiten möchte, nicht den gesamten Stack hochfahren muss. Zusätzlich bin ich am überlegen das Dritte Deployment also ACS und APS mittels einer DevOps Pipeline in EC2 zu deployen.&lt;/p&gt;
&lt;h1&gt;Prerequisites&lt;/h1&gt;
&lt;p&gt;Klar ist, dass du Docker brauchst. Falls du auf einem Windows oder Mac arbeitest empfehle ich dir den &lt;a href=&quot;https://www.docker.com/products/docker-desktop&quot;&gt;Docker Desktop&lt;/a&gt;. Nach der Installation bitte daran denken der Docker Umgebung mehr Memory zu Verfügung zu stellen da die default 2 GB viel zu wenig sind umd ACS zum Laufen zu bringen. Mindestens 12 GB wäre angebracht!&lt;/p&gt;
&lt;p&gt;Auch verwendet die ACS Docker Compose File private Images von Alfresco gehosted in quay.io . Für diese wäre es wichtig Zugangsdaten vom Alfresco Support zu erfragen. Wenn du diese hast einfach den folgenden Befehl ausführen und die Credentials eingeben:&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;Mehr oder weniger optional aber mein Beispiel im GitHub Repository verwendet Node&apos;s NPM für ein CLI Script Tool zum warten bis Alfresco fertig gebooted hat. Also am besten auch Node und NPM installieren.&lt;/p&gt;
&lt;h1&gt;Git Vorbereiten&lt;/h1&gt;
&lt;p&gt;Natürlich muss erstmal ein Git Repo erstellt werden. Ich hatte meins &lt;a href=&quot;https://github.com/mmuller88/alf-acs-aps&quot;&gt;alf-acs-aps&lt;/a&gt; genannt. Wie auch in meinem letzten &lt;a href=&quot;https://martinmueller.dev/start-script&quot;&gt;Alfresco Docker Projekt&lt;/a&gt; empfehle ich den &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Docker Alfresco Installer&lt;/a&gt; zu verwenden um das noch leere Git Repository vorzubereiten. Wie genau der Docker Alfresco Installer verwendet werden kann, beschreibe ich &lt;a href=&quot;https://github.com/mmuller88/alfresco-docker-installer&quot;&gt;hier&lt;/a&gt;. Beim installieren darauf achten, dass auch LDAP und ein SMTP Server ausgewählt wird. Falls du nicht mein GithUb Repo verwendest, müsstest du nun die APS 1.10 services in das Docker Compose Deployment integrieren. Ich empfehle dir das Deployment in drei Teile aufzuteilen. Alle drei werden in den nächsten Abschnitten erläutert.&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;Zuerst wird ein docker-compose-base.yml File erstellt welcher alle Services beinhaltet die für alle drei Deployments benötigt werden. Das sind in meinem Fall eine openLDAP und postgres Datenbank. Sowie ein Mail Server. Danach wird der ACS Docker Compose File erstellt. Das gesamte deployment lässt sich nun so starten:&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;und so stoppen:&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;Falls ein kompletter ACS Neustart mit leereren Datenbanken und anderen Storage erwünscht ist, einfach diese Befehle ausführen:&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;Das APS Deployment wird folgender Maßen gestartet:&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;und gestoppt wird es so:&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;Zum Erasen einfach das Folgende ausführen:&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-und-aps-deployment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#acs-und-aps-deployment&quot; aria-label=&quot;acs und 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 und APS Deployment&lt;/h2&gt;
&lt;p&gt;Achtung eine Warnung vorweg! Dieses Deployment ist sehr Memoryintensiv. Mindestens 16Gb sollte dein Laptop oder PC besitzen. Alternativ plan ich diese Variante in der Cloud auf EC2 zu deployen.&lt;/p&gt;
&lt;p&gt;Und so werden alle Services gestarted:&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;und so gestoppt&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;Und zum runterreißen einfach eingeben:&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;Ausblick&lt;/h1&gt;
&lt;p&gt;Wie angedeutet würde ich gerne das dritte Deployment also ACS und APS auf AWS EC2 bringen. Am liebsten sogar in einer schönen DevOps Pipeline, sprich commit nach master triggered ein Deploy nach EC2 wo dann dort automatisierte Tests ausgeführt werden wie zum Beispiel ob ACS und APS erfolgreich gebooted haben.&lt;/p&gt;
&lt;p&gt;SSO (Single Sign On) erlaubt es für die Alfresco Produkte sich nur noch einmal anmelden zu müssen. Das heißt wenn ich mich zum Beispiel in Share einlogge und dann Alfresco Digital Workspace öffne oder Ativiti App, muss ich mich nicht erneut einloggen. Dafür müsste AIMS Alfresco Identify Manager Service mit ACS konfiguriert werden und zusätzlich für Share dann noch die SAML amp.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Man muss nicht immer gleich die Kubernetes Keule auspacken wenn es um Container Orchestrierung geht. Auch Docker Compose kann hervorragend verwendet werden um Container zu orchestrieren. Es besteht sogar die möglichkeit komplexe Deployments in kleine Teilstücke aufzuteilen, welche nicht den Memory deines Laptops schonen sondern sich auch hervorragend für eine schnelle Iteration bei der Entwicklung eigenen. Also gerne mal ausprobieren ACS und APS mittels Docker Compose zu Deployen. Falls irgendwelche fragen sind, einfach anschreiben.&lt;/p&gt;
&lt;h1&gt;Kudos&lt;/h1&gt;
&lt;p&gt;An Thijs von der Tollen &lt;a href=&quot;https://discord.gg/XGQjUU&quot;&gt;Alfrescan Discord Channel Community&lt;/a&gt; für den Vorschlag das Docker Compose Deployment so auf zu teilen :).&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 mit Swagger]]></title><description><![CDATA[Ahoi AWS'ler und Swagger Fans Im letzten Post habe ich gezeigt wie AWS CDK genutzt werden kann als willkommende Alternative zu YAML als…]]></description><link>https://martinmueller.dev/cdk-swagger/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-swagger/</guid><category><![CDATA[de]]></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>Sat, 04 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 und Swagger Fans&lt;/p&gt;
&lt;p&gt;Im letzten Post habe ich gezeigt wie &lt;a href=&quot;https://martinmueller.dev/cdk-example&quot;&gt;AWS CDK&lt;/a&gt; genutzt werden kann als willkommende Alternative zu YAML als Infrastruckturbeschreibung. Während der Weiterentwicklung des CDK Beispiels ist mir ein Problem beim Umgang mit Swagger Files begegnet. Aber erstmal will ich erklären was die Swagger Definition überhaupt ist. Auch sei gesagt, dass seit 2018 die neue Version von Swagger OpenApi heißt. Wenn man AWS API Gateway nutzt, ist es praktisch zur Parameter Validierung wie zum Beispiel dem Query, Path und den Body Parameter, Swagger Files zu verwenden. Was genau Swagger ist und wieso ich es so toll finde beschreibe ich im nächsten Absatz.&lt;/p&gt;
&lt;h1&gt;Was ist 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; ist eine YAML oder JSON Template Sprache zur Beschreibung von RESTful APIs. Folgend beschreibe ich was super an Swagger ist. Erstens eigenen sich die Templates extrem gut als Dokumentation über die API selber, da aus dem Template eine schick aussehende HTML UI generiert werden kann, welche die API Endpoints sehr gut beschreibt. Eine solche UI ist im Titelbild dieses Blogposts zu sehen. Noch genialer ist die UI kann direkt zum Testen der Endpoints genutzt werden, also zum Senden und Empfangen von Requests und Responses. Viele API Schnittstellen, wie es auch AWS API Gateway eine ist, bieten es and die Parameter Validierung der Requests über Swagger Files zu machen. Was mit Parametervalidierung gemeint ist versuche ich anhand des folgenden Beispiels zu erklären:&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;Hier ist ein Parameter vom Typ Query zu sehen sehen. Das bedeutet dieser würde in der URL in etwa so aussehen&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;Mit der Parametervalidierung kann ich dann bestimmte Eigenschaften des Parameters definieren, wie hier der name &lt;strong&gt;userId&lt;/strong&gt; ob er required ist und welchen Typ der value haben soll, in unserem Fall als vom typ string.&lt;/p&gt;
&lt;p&gt;Auch sehr mächtig ist die Eigenschaft, dass es möglich ist aus Swagger Files &lt;a href=&quot;https://swagger.io/tools/swagger-codegen/&quot;&gt;Client Libaries zu generieren&lt;/a&gt;. Alfresco macht das zum Beispiel mit dem &lt;a href=&quot;https://api-explorer.alfresco.com/api-explorer/&quot;&gt;API-Explorer&lt;/a&gt; (Näheres auf &lt;a href=&quot;https://github.com/Alfresco/rest-api-explorer&quot;&gt;GitHub Api-Explorer&lt;/a&gt;) und &lt;a href=&quot;https://www.alfresco.com/abn/adf/&quot;&gt;ADF&lt;/a&gt; (oder &lt;a href=&quot;https://github.com/Alfresco/alfresco-js-api&quot;&gt;ADF JS Github&lt;/a&gt;). Dort wird zum Beispiel aus dem &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; die eine JavaScript API Library erzeugt, welche als Wrapper für die API Requests genutzt werden kann und auch wird 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;Auch cool ist, &lt;a href=&quot;https://www.postman.com/automated-testing&quot;&gt;Postman&lt;/a&gt; bietet eine Importierfunktion für Swagger Files. Dann wird daraus gleich eine Collections erzeugt. Das ist sehr praktisch, wenn man anfangen möchte die Requests in Postman zu schreiben.&lt;/p&gt;
&lt;h1&gt;AWS Api Gatway mit Swagger&lt;/h1&gt;
&lt;p&gt;Die ganzen Features vom vorherigen Abschnitt klingen schon sehr verlockend oder? Wie toll das auch AWS API Gateway es anbietet, Swagger Files aus dessen Deployments zu &lt;a href=&quot;https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-export-api.html&quot;&gt;extrahieren&lt;/a&gt; und zu importieren, wenn Cloudformation oder CDK verwendet wird. Leider im Zusammenhang mit &lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt;, lassen sich extrahierte Swagger Files nicht so einfach wiederverwenden für dessen Beschreibung. Das größte Problem ist, dass wenn zum Beispiel ein Lambda geupdated wird, sich dan logischerweise auch dessen ARN ändert. Allerdings die vom API Gateway extrahierten Swagger Files verwenden genau diese ARNs wenn Lambda als Backendimplementierung für einen Endpoint benutzt wird. Und da sich die ARN ändert sind diese outdated im swagger file. Nachfolgend ist ein Swagger Snippet und dort sieht man die Arn über die ich spreche hinter dem &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;
  &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;get&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;&apos;200&apos;&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; Ok
          &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 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;&apos;401&apos;&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; Authorization information is missing or invalid
          &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 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;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;uri&lt;/span&gt;&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;aws&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;apigateway&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;lambda&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;path/2015&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;03&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;31/functions/arn&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;aws&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 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;function&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
        &lt;span class=&quot;token key atrule&quot;&gt;passthroughBehavior&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 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; POST
        &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; aws_proxy
      &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;$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;
      &lt;span class=&quot;token key atrule&quot;&gt;x-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;Das AWS CDK Team weiß über dieses Problem bescheid und es ist auf der Roadmap. So hoffentlich wenn du diesen Beitrag ließt ist der folgende Workaround nicht mehr notwendig. Zur Vollständigkeit liste ich hier die related Issues auf:&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;Um des Problem zu lösen habe ich mein Travis so konfiguriert, dass CDK zweimal deployed wird. Beim ersten Deploy wird kein Swagger File benutzt und beim zweiten wird dann ein geniertes Swagger File verwendet. Wirklich interessant ist wie ich an das generierte Swagger File komme. Folgend versuche ich den Prozess zu beschreiben, aber bitte schaut auch in &lt;a href=&quot;https://github.com/mmuller88/cdk-swagger&quot;&gt;meinem GitHub Repo&lt;/a&gt; (dort in .travis) nach wie ich diesen Workaround implementiert habe.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ich deploye oder Swagger File mit:&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;Aufpassen WITH_SWAGGER is eine env Variable im CDK Deployment File index.ts . Damit wird programmatisch keine Swagger File für das Deployment verwendet.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Nun kann ich mit der AWS CLI das Swagger File vom API Gateway extrahieren:&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;Der generiert Swagger File tmp/swagger_new.yaml sieht dan in etwas so aus:&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;
    &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;2020-03-29T16:59:22Z&apos;&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; 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
&lt;span class=&quot;token key atrule&quot;&gt;basePath&lt;/span&gt;&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;
    &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;get&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;&apos;200&apos;&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; Ok
                &lt;span class=&quot;token key atrule&quot;&gt;&apos;401&apos;&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; Authorization information is missing or invalid
            &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;uri&lt;/span&gt;&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;aws&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;apigateway&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;lambda&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;path/2015&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;03&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;31/functions/arn&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;aws&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 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;function&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
                &lt;span class=&quot;token key atrule&quot;&gt;passthroughBehavior&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 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; POST
                &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; aws_proxy
            &lt;span class=&quot;token key atrule&quot;&gt;x-amazon-apigateway-request-validator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Validator
        &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 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;Das sieht schon sehr gut aus. Allerdings fehlt jetzt noch die besagt Parameter Validierung. Dafür muss eine zweite Swagger definition erstellt werden templates/swagger_validations.yaml und sieht in etwas so aus:&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;
    &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;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&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;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; alfUserId
            &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;required&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 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;$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;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Was wir jetzt aber wollen ist ein merge beider swagger Files. NPM bietet ein nützliches Tool zum mergen von 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;Die Swagger Definition tmp/swagger_full.yaml beinhaltet nun die aktuelle LambdaUri und die Parameter Validierung:&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;
  &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;2020-03-29T16:59:22Z&apos;&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; 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.eu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;.amazonaws.com
&lt;span class=&quot;token key atrule&quot;&gt;basePath&lt;/span&gt;&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;
  &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;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&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;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; alfUserId
            &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;required&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 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;$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;
        &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;&apos;200&apos;&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; Ok
            &lt;span class=&quot;token key atrule&quot;&gt;&apos;401&apos;&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; Authorization information is missing or invalid
        &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;uri&lt;/span&gt;&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;aws&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;apigateway&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;lambda&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;path/2015&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;03&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;31/functions/arn&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;aws&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 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;function&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
            &lt;span class=&quot;token key atrule&quot;&gt;passthroughBehavior&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 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; POST
            &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; aws_proxy
        &lt;span class=&quot;token key atrule&quot;&gt;x-amazon-apigateway-request-validator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Validator
    &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 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;Nun kann dieses Swagger File im zweiten CDK Deployment angewendet werden:&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;Achtung!: Immer gut darauf aufpassen das auch ein neues Stage Deployment in AWS API Gateway kreiert wurde. Ich mache das in Travis mit der 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;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Swagger Definitions eigenen sich hervorragend zur Erstellung, Editierung, Dokumentation und Testung vom APIs wie der von AWS Api Gateway. Sie eigenen sich nicht nur direkt im Backend um dieses Backend zu erstellen, sondern sind nützlich sogar im Frontend da aus den Swagger Definitions Client Libraries generiert werden können und es dem Frontendentwickler gelingt durch die Swagger Dokumentations UI das Backend viel besser und in kürzerer Zeit zu verstehen.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 mit Travis Deployment]]></title><description><![CDATA[Ahoi AWS'ler Für ein privates Projekt habe ich mich in den letzten Tagen an ein AWS CDK Example gemacht. AWS bietet eine Palette von tollen…]]></description><link>https://martinmueller.dev/cdk-example/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-example/</guid><category><![CDATA[de]]></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>Sat, 28 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;Ahoi AWS&apos;ler&lt;/p&gt;
&lt;p&gt;Für ein privates Projekt habe ich mich in den letzten Tagen an ein AWS CDK Example gemacht. AWS bietet eine Palette von tollen &lt;a href=&quot;https://github.com/aws-samples/aws-cdk-examples&quot;&gt;AWS CDK Beispielen&lt;/a&gt;. Die Erfahrung die ich gemacht habe, war so gut, dass ich mich entschlossen habe, einen Blogpost darüber zu schreiben. Schon sehr früh in meiner AWS Karriere durfte ich mich mit CloudFormation beschäftigen. Seit neuem scheint ein neues Kind im Block zu sein mit Namen AWS CDK (Cloud Development Kit), welches bevorzugt als Sprache zur Beschreibung der Infrastruktur in AWS genutzt werden kann. CDK verspricht eine willkommende Alternative zu Cloudformation zu sein, da man anstelle wie üblich diese im eher komplexen YAML schreiben muss, werden im CDK richtige Programmiersprachen wie Java, Python, JS oder Typescript unterstützt. Ich finde das ein super Idee da man, wenn man sich für z.B. Typescript als Sprache für die Lambdas entschieden hat, auch diese für das CDK verwenden kann.
Mein Beispiel Code &lt;a href=&quot;https://github.com/mmuller88/cdk-example&quot;&gt;CDK Example Repo&lt;/a&gt; ist auf GitHub. In den nächsten Abschnitten werde ich kurz die einzelnen Schritte für die Repo Erstellung beschreiben.&lt;/p&gt;
&lt;h1&gt;Das wird Benötigt&lt;/h1&gt;
&lt;p&gt;Wenn du AWS CDK ausprobieren möchtest, benötigst du einen AWS Account. Darüber hinaus brauchst du AWS CLI Credentials, welche es deinem Deployment erlauben, Ressourcen in deinem AWS Account zu nutzen. Üblicherweise erstellt man dafür einen &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;. Wichtig dabei ist, dass du dir die Zugangsdaten also der die Access Key Id und der Secret Access Key gut abspeicherst. Diese werden nachher im Deployment benötigt.
Das verwendete AWS Beispiel verwendet NPM als Package Manager. Das bedeutet es kümmert sich um die Dependencies wie zum Beispiel dem aws-cdk welches mit dem folgenden command installiert wird:&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 &lt;a href=&quot;https://nodejs.org/en/download/&quot;&gt;hier&lt;/a&gt; erhältlich.&lt;/p&gt;
&lt;h1&gt;Git Repo Vorbereiten&lt;/h1&gt;
&lt;p&gt;So nun geht es los. Zuerst erstellen wir unser GitHub Repository welches noch komplett leer ist. Bei mir habe ich es &lt;strong&gt;cdk-example&lt;/strong&gt; genannt. Dann sollte das &lt;a href=&quot;https://github.com/aws-samples/aws-cdk-examples&quot;&gt;AWS CDK Examples&lt;/a&gt; Repo geforkt und local ausgecheckt sein. Mit dem Hintergrund, dass wir so einfacher Cherry Picking betreiben können und somit einfach die für uns interesannten Beispiele darin in unser Repository kopieren können.&lt;/p&gt;
&lt;p&gt;Wenn man sich das AWS CDK Examples Repository anschaut hat man nun sprichwörtlich die Qual der Wahl. Ich selber kann die Beispiele von der Typescript Kategorie empfehlen da sie reichlich sind und Typescript anscheinend immer beliebter wird als Programmiersprache. Auch empfehle ich mit dem &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 anzufangen, da es schon sehr viele AWS Services beinhaltet wie API Gateway, Lambda und DynamoDB. Das Beispiel is ein einfacher CRUD Storage welches mit DynamoDB als DB fungiert. Am besten den bestehenden Quellcode nicht abändern und erstmal versuchen ihn nur zum Laufen zu bekommen. Ich selber hatte eine kleine Schwierigkeit. Das Beispiel hat eine missing Dependency. Undzwar fehlt die NPM uuid Library, welche zur generierung von IDs verwendet wird. Dafür muss ins src/ Verzeichnis gewechselt werden und die folgenden Commands ausgeführt werden:&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;Auch muss der Code etwas angepasst werden, da sich die uuid mit den Versionen etwas geändert hat. Alternativ kann auch einfach aus meinem &lt;a href=&quot;https://github.com/mmuller88/cdk-example&quot;&gt;publizierten GitHub Repo&lt;/a&gt; kopiert werden. Im nächsten Abschnitt bringen wir dann das Beispiel zum laufen.&lt;/p&gt;
&lt;h1&gt;CDK Manuell Deployen&lt;/h1&gt;
&lt;p&gt;Im vorherigen Abschnitt haben wir das Repo soweit vorbereitet, jetzt wollen wir natürlich deployen! Da wir unser Deployment in AWS haben, muss sichergestellt werden, dass die Zugangscredentials richtig eingestellt sind. In der &lt;strong&gt;Das wird Benötigt&lt;/strong&gt; haben wir bereits die Credentials erhalten. Es gibt verschiedene Möglichkeiten diese Credentials deinem Build zur Verfügung zu stellen. Das automatisierte Deployment in Travis funktioniert mit Environment Variablen. Für das manuelle Deployn ist es komfortabeler die Credentials im aws config folder zu erstellen.  dafür einfach die folgenden Datein einfügen:&lt;/p&gt;
&lt;p&gt;~/.aws/conf und ~/.aws/credentials ebenfalls! Für Windows Nutzer einfach deinen Benutzerordner anstelle der ~ benutzen. Mit folgenden Content befüllen:&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 = fIr...
region = eu-west-2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Du solltest dir eine Region aussuchen welche dicht zu dir sind und viel Funktionalität anbieten. Da die Frankfurter Region oftmals hinterher ist mit neuen Features, habe ich mich für die London Region eu-west-2 entschieden.&lt;/p&gt;
&lt;p&gt;Jetzt ins Repo wechseln und die folgenden Befehle ausführen:&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;Die npm install Befehle laden die Dependencies. In der Regel müssen diese nur selten ausgeführt werden. Der Run Befehl hingegen immer wenn Änderungen durchgeführt worden sind. Interessante Tatsache ist, dass dieser die TypeScript Files in JavaScript Files konvertiert. Da TypeScript ein Superset vom JavaScript ist, muss man so das Tooling um TypeScript nicht neu erfinden und nutzt einfach die vorhandenen von JavaScript. Aber aufpassen und nicht verwirren lassen von diesen generierten JS Files. Eventuell machst du deine Änderungen genau an diesen und wunderst dich, warum die Änderungen nicht im Deployment geschehen.&lt;/p&gt;
&lt;p&gt;Als nächstes muss CDK so konfiguriert werden, dass es weiß welcher Account und welche Region genutzt werden soll. Warum CDK das nicht aus dem AWS Folder generieren kann, verstehe ich allerdings auch nicht. Dann kann CDK deployed werden:&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;Auch interessant mit:&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;Kann man sich das generierte CloudFormation Template anschauen.&lt;/p&gt;
&lt;h1&gt;Automation mit Travis&lt;/h1&gt;
&lt;p&gt;Noch hält sicher der manuelle Aufwand für das Deployment gering, aber das könnte bei mehr werdender Komplexität sicher ändern. Von daher habe ich bisher super Erfahrungen gemacht, wenn ich so viel wie möglich davon automatisiere. Und nunja stellt euch mal vor wie cool es ist einfach nur mit einem Push zu master die Produktionsumgebung zu ändern. Einen kleinen Vorgeschmack wie das aussehen könnte beschreibe ich hier. Auch sei wieder gesagt, dass ihr euch meine Travis Definition gerne anschauen könnte hier &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;Was ich dort in Travis mache ist recht einfach erklärt. Ich führe einfach nur die manuellen Deployschritte von der vorherigen Sektion in Travis aus. Da Travis meine AWS Credentials in Form von verschlüsselten Environmental Variables hat, erlaube ich es es in meinem AWS Account Ressourcen zu manipulieren. Die folgenden Environmental Variablen waren dafür nötig: 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;Nur das Deployment nicht mehr manuell ausführen zu müssen, scheint auf den ersten Blick vielleicht nicht sehr nützlich, aber glaubt mir es lohnt sich! Nachdem das CDK Deployment fertig ist werden dann Postman Tests in Form von Requests und Response Validations ausgeführt. Näheres dazu beschreibe ich in der nächsten Sektion.&lt;/p&gt;
&lt;h1&gt;Stack Testing mit Postman&lt;/h1&gt;
&lt;p&gt;Ich denke mittlerweile weiß jeder über &lt;a href=&quot;https://www.postman.com/automated-testing&quot;&gt;Postman&lt;/a&gt; bescheid. Es ist ein geniales Tool zum testen von APIs, die mittels Request und Responses arbeiten. In meinem Fall ist das ein REST API welches durch AWS API Gateway definiert ist. In meinem GitHub repository habe ich eine kleine Sammlung von Requests und Response Tests, welches in Postman als Collections bezeichnet werden, zusammengestellt. Diese können dann einfach mittels der CLI &lt;a href=&quot;https://github.com/postmanlabs/newman&quot;&gt;Newman&lt;/a&gt; zum Ausführen von den mit Postman erstellten Collections genutzt werden. Newman muss dann natürlich vorher auf der Build Maschine installiert sein. In meinem Repo mache ich das via NPM im package.json. Dazu einfach den folgenden Befehl ausführen:&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;Der kreative Prozess des Collections schreiben sind dann so aus, dass in Postman eine neue Collection erstellt wird und Requests geschrieben werden. Das Request läuft gegen die REST API und gibt ein Response zurück. Das Response kann dann validiert werden. Postman bietet für die Validierung der Responses eine Umfangreiche Möglichkeiten. So kann man einfach den Statuscode im Response mit dem erwarteten Wert abgleichen, andere Erwartungswerte vergleichen, Variablen erstellen für ide nächsten Requests genutzt werden können und vieles vieles mehr. Ein Tip von mir, versucht die Menge an Tests gering zu halten.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;AWS noch recht neues CDK ist ein tolles Werkzeug zum erstellen von AWS Cloudformation Stacks. Sehr toll finde ich, dass man es in der gleichen Programmiersprache schreiben kann in der auch eventuell verwendete Lambdas sind. Kombiniert mit automatischen Deployment und Tests zum Beispiel mit Travis, erlaubt es schnell und effizient neue Änderungen am Stack durchzuführen. Ich glaube auch, dass es dadurch nicht oder weniger nötig ist Lambdas lokal testen zu müssen. Wenn ihr Hilfe bei eurem AWS CDK Projekt braucht, zögert nicht mich oder die hilfsbereite &lt;a href=&quot;https://gitter.im/awslabs/aws-cdk&quot;&gt;CDK Gitter Community&lt;/a&gt; zu fragen.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 für den Alfresco Docker Installer]]></title><description><![CDATA[Hi Alfrescans, Ich habe tolle Erfahrungen gesammelt in meinem letzten Projekt mit dem Alfresco Docker Installer. Näheres darüber einfach in…]]></description><link>https://martinmueller.dev/start-script/</link><guid isPermaLink="false">https://martinmueller.dev/start-script/</guid><category><![CDATA[de]]></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>Sat, 21 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;Ich habe tolle Erfahrungen gesammelt in meinem letzten Projekt mit dem &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt;. Näheres darüber einfach in meinem vorherigen &lt;a href=&quot;http://martinmueller.dev/alfresco-docker-installer&quot;&gt;Blogpost&lt;/a&gt; nachlesen. Nun bin ich natürlich gespannt darauf sinnvolle neue Features zu kontributieren. Eines davon ist das Start Script welches als Wrapper für das Docker Compose File genutzt werden kann. In meinen bishering Alfresco Docker Compose Projekten habe ich immer dieses Script implementiert da es einige wertvolle Zusatzfunktionen bietet. Welche das sind werden im nächsten Abschnitt erklärt. Für mich macht es daher Sinn das Start Script dem Installer zur Verfügung zu stellen.&lt;/p&gt;
&lt;h1&gt;Features&lt;/h1&gt;
&lt;p&gt;Das wohl wichtigste Feature is eine eingebaute warte Routine. Dieses wartet solange bis ACS fertig gebooted hat. Das ist zum Beispiel sehr nützlich wenn man nach dem Start von ACS tests auführen möchte mit Tools wie Postman. Auch können Daten via REST API geladen werden, wenn ACS fertig mit booten ist. Die warte Routine ist mit NPM&apos;s &lt;a href=&quot;https://www.npmjs.com/package/wait-on&quot;&gt;wait-on&lt;/a&gt; implementiert. Es macht Sinn auf die breite Palette an Tools im public NPM Repository zurückzugreifen, da ich dann diese nicht selber implementieren musst und außerdem sind diese in der Regel gut getested und bieten wenig Freiraum für Fehlerfälle.&lt;/p&gt;
&lt;p&gt;Das nächste Feature ist besonders wichtig für mich da ich mit dem Windows arbeite. Wenn man versucht Docker Compose mit Windows auszuführen bekommt man eventuell ein Problem mit den Volumes, da diese nicht die Windows Path schreibweise ootb unterstützen. Glücklicherweise hat die Docker Compose Community eine Lösung bereitgestellt. Es muss einfach die folgende Environment Variable gesetzt werden bevor Docker Compose gestartet wird:&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;Das wird nun vorher gemacht wenn man das Start Script zusätzlich mit dem -wp flag startet.&lt;/p&gt;
&lt;p&gt;Die nächsten Features haben es bisher noch nicht in den Alfresco Docker Installer geschafft, was sich aber bald ändern könnte und welche ich persönlich schon viel bei meinen Deployment nutze. Es ist möglich mit -hi und -hp die Host IP und den Host Port dynamisch mit dem Start Script zu setzen. Ich finde das sehr praktisch wenn man sich in Umgebungen befindet welche öfter mal die IP wechseln. Zurzeit löst das aber der Installer so, dass er bei der Installation die Host IP und den Host Port abfragt. Es ist also schon konfigurierbar, wenn auch nur während der Installation selbst.&lt;/p&gt;
&lt;p&gt;Mehr Features sind zwar möglich aber zurzeit nicht implementiert. Z.B. Das Laden von Testdaten mit dem REST API. In meinem &lt;a href=&quot;http://martinmueller.dev/adf-app&quot;&gt;ADF AI Prototypen&lt;/a&gt; habe ich noch zusätzlich ein -b für build the Angular Webapp und ein -aca so das nur der ACA Container redeployed wird um ein schnelles Entwickeln mit der ACA Webapp zu gewährleisten. Wie genau ich das Start Script contributed habe, stelle ich im nächsten Abschnitt vor.&lt;/p&gt;
&lt;h1&gt;Contribution&lt;/h1&gt;
&lt;p&gt;Zuerst sollte ein Fork vom &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt; kreiert werden. Auf diesem können dann die Anpassungen gemacht werden. In meinem Fall ist es das Start Script mit Filenamen start.sh. Ich habe das Script unter template/scripts abgespeichert und das Yeoman Setup so eingestellt, dass das Script optional hinzugefügt werden kann, sehr ähnlich wie auch der LDAP Service hinzugefügt wird. Alle Änderungen sollten auf deinen Fork in Form eines Remote Branches gesichert werden. Dafür muss zunächst ein lokaler Branch erzeugt und Änderungen gepushed werden:&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;Sind nun alle Änderungen vollzogen und ausgiebig getestet, kann ein Pull Request zum Alfresco Docker Installer Repository erstellt werden. Dafür geht man einfach auf die Installer Github Seite. Dort erscheint dann ein Create Pull Request Button.&lt;/p&gt;
&lt;p&gt;Oh ja eine Sache bitte noch beachten. Wenn du ein neues Feature contributen willst wäre es sehr toll und best practice wenn du auch dazu einen Test schreibst, welcher garantiert dass das neue Feature funktioniert. Ich habe das im .travis File gemacht. Nun werden Deployments und Start von Alfresco mit und ohne zur Hilfenahme des Start Scriptes getestet.&lt;/p&gt;
&lt;h1&gt;Ausblick&lt;/h1&gt;
&lt;p&gt;Als nächstes möchte ich gerne Alfresco&apos;s neuen Alfresco Identity Management Service auch AIMS genannt als Kontribution bereit stellen. Dafür wird ein Keycloak Container hinzugefügt, sowie die Alfresco Properties angepasst. AIMS macht nur Sinn wenn man auch einen Identity Provider besitzt. Also soll AIMS nur hinzugefügt werden, wenn LDAP während der Installation ausgewählt wird.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Dieser Artikel beschreibt eine kurz Übersicht zu meiner ersten Kontribution zu dem Alfresco Docker Installer. Zu einem nutze ich das Repository bereits für meine Projekte und es bot mir die perfekte Möglichkeit den Yeoman template Installer besser zu verstehen. Das Start Script bietet viele neue zusätzliche Funktionen. Wie man eine Contribution machen kann, wurde ebenfalls ausführlich beschrieben. Hast du eventuell auch eine tolle Idee wie man den Installer verbessern könnte? Ich freue mich auf dein Feedback.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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 und Jars mit Docker Testen]]></title><description><![CDATA[Hi Alfrescans, In diesem Artikel werde ich beschreiben wie man Docker nutzen kann um Amps und Jars Erweiterungen für ACS zu testen. Für…]]></description><link>https://martinmueller.dev/alfresco-docker-installer/</link><guid isPermaLink="false">https://martinmueller.dev/alfresco-docker-installer/</guid><category><![CDATA[de]]></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>Sun, 15 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 diesem Artikel werde ich beschreiben wie man Docker nutzen kann um Amps und Jars Erweiterungen für ACS zu testen. Für einen Kunden von &lt;a href=&quot;https://www.object.ch&quot;&gt;OBJECT&lt;/a&gt; wurden Share Customizations sowie Costume Content Models entwickelt, welche ich schnell und einfach weiterentwickeln möchte.&lt;/p&gt;
&lt;p&gt;Interassant hinzukam für mein Projet, dass die Amps für ein ACS 5.2.6 Deployment geschrieben wurden und Docker als Deployment erst ab ACS 6.0 supported ist. Es war also relativ challenging das Docker Deployment so anzupassen, dass alles funktioniert. Wenn deine Erweiterungen für ACS 6.0 oder neuer geschrieben wurden, sollte es einfacher sein.&lt;/p&gt;
&lt;h1&gt;Warum Docker Deployment?&lt;/h1&gt;
&lt;p&gt;Der altmodische Weg ist es die lokal kompilierten Amps und Jars an einem lokalen ACS Deployment zu testen, welches komplett ohne Docker konfiguriert wurde. Das bedeutet Tomcat muss installiert und ACS mit all seinen Dependencies muss auch vorhanden sein. Klar der altmodische Installer hilft dabei, es ist trotzdem eine zeitaufbringende und wenig befriedigende Aufgabe Alfresco so installieren zu müssen. Zusätzlich kommt dann ja noch das man die Amps immer per Hand installieren und evtl. deinstallieren muss. Nicht schön!&lt;/p&gt;
&lt;p&gt;Docker Container adressieren genau diese Probleme. Mit Hilfe des Dockerfiles kann ich niederschreiben welche Konfigurationsschritte unternommen werden sollen. Mit Git kann das sogar versioniert passieren und Deployments können blitzschnell zu vorherigen funktionierenden Versionen reverted werden. In diesen Dockerfiles kann man die Installation des Tomcats sowie die Konfiguration von ACS und vieles mehr niederschreiben.&lt;/p&gt;
&lt;p&gt;Klingt nach ner Menge Arbeit? Nö! Alfresco maintained ACS Docker Deployments mit Version 6.0 oder neuer. Wie so ein einfaches Docker Deployment, wobei die Container mit Docker Compose orchestriert werden lässt sich hier bestauen für &lt;a href=&quot;https://github.com/Alfresco/acs-deployment/tree/master/docker-compose&quot;&gt;ACS Enterprise&lt;/a&gt; und hier für &lt;a href=&quot;https://github.com/Alfresco/acs-community-deployment/tree/master/docker-compose&quot;&gt;ACS Community&lt;/a&gt;. Die Docker Images welches diese Deployment sind hier &lt;a href=&quot;https://github.com/Alfresco/acs-packaging/tree/master/docker-alfresco&quot;&gt;ACS Enterprise Image&lt;/a&gt; und hier &lt;a href=&quot;https://github.com/Alfresco/acs-community-packaging/tree/master/docker-alfresco&quot;&gt;ACS Community Image&lt;/a&gt;. Zugegeben diese Deployments und Images sind recht limitiert in Punkto Customizations. Das ist zwar gut für einen schnellen Einstieg, erlaubt uns aber nicht unsere lokal erstellten Amps zu testen. Wie das ermöglicht wird, beschreibe ich im nächsten Kapitel.&lt;/p&gt;
&lt;h1&gt;Git Repo Vorbereiten&lt;/h1&gt;
&lt;p&gt;Falls der Build Code eure Amps und Jars in verschieden Git Repos liegen, macht es Sinn diese auf einem Repo zu vereinigen um die Docker Image Erstellung zu erleichtern. Z.B. könnte die repo und share amp in gleichnahmgen Unterverzeichnissen liegen. Falls Maven als Build und Packagingtool verwendet wurde, ist das einfach zu realisieren mit Parent Poms. Nach der möglichen Umstrukturierung muss der Build getestet werden, ob auch die Amps oder Jars erstellt werden. Bei mir wurde das durch das durch den einfachen Maven Befehl ausgeführt:&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;Nun soll das Docker Backend installiert werden. Die Orchestrierung der Container soll mit Docker Compose geschehen. Zum Glück gibt es dafür den &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt; der einfach bedienbarer, mit Yeoman unterstützter, Template Installer ist und schon eine breite Palette an Installoptionen wie der ACS Version, ob LDAP verwendet werden soll usw. bietet. Ich würde vorschlagen einfach erstmal einen Ordner mit namen docker im Git Repo zu erstellen und in diesem das Docker Compose Backend mit dem &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer#installation&quot;&gt;Alfresco Docker Installer zu installieren&lt;/a&gt;. Nach der installation sollte das Deployment mit&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 up --build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;hochgefahren und die Urls getestet werden welche da sind:&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;Wenn alles funktioniert hat, einfach das Deployment runterfahren mit:&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;Im nächsten Abschnitt wird erklärt wie die Share oder Repo Amp / Jar in die Image mit eingebunden werden kann.&lt;/p&gt;
&lt;h1&gt;Share und Repo Images Anpassen&lt;/h1&gt;
&lt;p&gt;Nun isst es an der Zeit die Share und Repo Modifikationen mittels Amps oder Jar in die Image zu gießen. Idealerweise sollten die frisch kompilierten Amps / Jars aus dem target Folder dafür genutzt werden. am einfachsten geht dass wenn wir das Dockerfile vom docker/alfresco nach repo/ und docker/share nach share/ verschoben werden. Dadurch erlauben wir Docker bei der Bildung der Image auf das jeweils dortige target Verzeichniss zuzugreifen kann. Jetzt einfach in der repo und share Dockerfile die Anweisung setzen, dass die Amps / Jars aus dem target Folder in die Image kopiert werden wie hier z.B.:&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;Nun muss noch das docker/docker-compose.yaml File geändert und die Verzeichnisse für die Repo und Share Image angepasst werden. In unseren Setup sehe dass dan so aus für 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;Und so für 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 für ACS 5.2&lt;/h1&gt;
&lt;p&gt;Wenn ihr auch so wie ich Amps oder Jars für ein ACS 5.2 Deployment testen wollt, kommen ein paar Schwierigkeiten hinzu. Es kann passieren, dass die verwendeten Dependencies für die 5.2 Amp / Jar nicht mehr kompatibel mit dem ACS Docker Deployment sind. Auffallen wird das durch Errors wärend ACS gebooted wird. Der erste Schritt ist herauszufinden welche Dependencies (in der Regel Jar files auf dem Tomcat Classpath) Probleme verursachen. Es empfiehlt sich dann ein Maven Profil für die 6.2 amp zu kreieren, welches dann die Dependencies mit der richtigen Version nachlädt.&lt;/p&gt;
&lt;p&gt;Dann müssen diese auch im Dockerfile gelöscht werden. Nicht entmutigen lassen, dass kann schon recht Haaresträubend und Zeitaufwendig werden! Bei mir sah das in etwa dann so aus:&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;Zum testen kann dann die Amp / Jar die mit dem 6.2 Profil gebaut wurde, verwendet werden. Aber aufpassen für das 5.2 Deployment muss die Amp / Jar ohne das 6.2 Profil verwendet werden, ansonsten kann es zu anderen Dependency Problemen kommen!&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Amps und Jars sind immer noch die beliebteste Methode Customizations an ACS und Share durchzuführen. Diese lokal zu testen, muss auch nicht aufwendig sein, wenn man Docker verwendet. Ich hoffe ich konnte dich animieren zukünftig mal Docket für die Erweiterungen zu benutzen. Falls ja schreib mir doch bitte deine Erfahrung :).&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Meine Smart Home Erfahrung]]></title><description><![CDATA[Hallo Leute. Im Oktober 2019 hatte ich die großartige Gelegenheit, mir ein Haus in der schönen deutschen Stadt Ludwigslust zu kaufen. Es ist…]]></description><link>https://martinmueller.dev/smart-home-de/</link><guid isPermaLink="false">https://martinmueller.dev/smart-home-de/</guid><category><![CDATA[de]]></category><category><![CDATA[2020]]></category><category><![CDATA[smart-home]]></category><category><![CDATA[smart-life]]></category><category><![CDATA[amazon]]></category><pubDate>Sat, 07 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;Hallo Leute.&lt;/p&gt;
&lt;p&gt;Im Oktober 2019 hatte ich die großartige Gelegenheit, mir ein Haus in der schönen deutschen Stadt Ludwigslust zu kaufen. Es ist ein altes, aber kürzlich renoviertes schönes Haus. Da ich mich sehr für Technik interessiere, konnte ich es kaum abwarten, ein paar coole Smart Home Sachen auszuprobieren.&lt;/p&gt;
&lt;p&gt;Ich habe tolle Zeiten mit den folgenden Smart Home Geräten gemacht:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Bulbs Teckin&lt;/strong&gt;: Das sind Smart Bulbs mit integriertem WLAN. Sie passen in normale Fassungen für herkömmliche Beleuchtung.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Sockets Teckin&lt;/strong&gt;: Schön designte Steckdosen, die ihr zwischen das elektrisches Gerät und der Steckdose platzieren könnt, um es fernzusteuern. Es funktioniert auch mit WLAN.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Garage Door&lt;/strong&gt;: Eine coole Erweiterung für des Garagenmotors. Damit kann das Garagentor über WLAN ferngesteuert werden.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thermostate&lt;/strong&gt;: Ein schönes kleines Gerät, um die Heizungszeiten zu bestimmen. Diejenigen die ich getestet hatte, hatten keine WLAN- oder Bluetooth-Verbindung.&lt;/p&gt;
&lt;p&gt;Weiter unten im Artikel habe ich Links zu diesen Geräten bereitgestellt. Meine oberste Priorität war es, langfristig Kosten wie Strom oder Gas zu sparen und die Lebensqualität von mir und meiner Frau zu verbessern.&lt;/p&gt;
&lt;p&gt;Es gibt Dutzende von Smart Home Lösungen, und du musst vorsichtig sein, welche du verwenden möchtest, da Gadgets von verschiedenen Anbietern nicht immer gut zusammenspielen.&lt;/p&gt;
&lt;p&gt;Ich habe mich für Gadgets entschieden, die sich mit der &apos;Smart Life&apos;-App gesteuert werden können, da sie ein riesiges Angebot für alle Arten von Smart Home-Geräten bietet.&lt;/p&gt;
&lt;h1&gt;Welche Funkfrequenz?&lt;/h1&gt;
&lt;p&gt;Es ist wichtig zu erwähnen, dass alle meine Smart Home-Geräte nur in einem drahtlosen 2,4-GHz-Netzwerk funktionieren. Es ist unwahrscheinlich, dass du Geräte für das 5-GHz-Netzwerk findest. Mit 2.4 GHz sind die Länge der Wellen im Vergleich zu 5 GHz länger und dringt somit besser durch Wände, hat aber dafür eine geringere maximal erreichbare Bandbreite. Tatsächlich benötigen Smart Home-Geräte keine hohe Bandbreite, das ist also in Ordnung. Stell sicher, dass beide Netzwerkfrequenzen auf deinem Router eingerichtet sind!&lt;/p&gt;
&lt;h1&gt;Intelligente Glühbirnen Überall&lt;/h1&gt;
&lt;p&gt;Ich habe mich für den Kauf der Smart WLAN LED-Leuchten von Teckin entschieden. Diese können in einem Bündel gekauft werden, um ein bisschen zu sparen. Was soll ich sagen, ich liebe diese Smart-Lampen wirklich. Ich habe bereits Geld gespart, indem ich nur die vorhandenen Lampen ersetzt habe, die mit 40 W betrieben wurden, um die Smart-Lampen zu verwenden, die nur 8 W zum Leuchten benötigen.&lt;/p&gt;
&lt;p&gt;Da es vorkommen kann, dass man mal vergisst das Licht auszuschalten, habe ich jede smarte Glühbirne so konfiguriert, dass sie sich um 1 Uhr morgens selber ausschaltet, da zu diesem Zeitpunkt normalerweise niemand mehr wach ist. Leider gibt es einige Stellen im Haus, an denen das WLAN-Signal nicht stark genug ist. Für diesen Fall habe ich keine intelligente Glühbirne installiert. Ich habe nur die 40 W gegen eine einfache 8 W LED ausgetauscht.&lt;/p&gt;
&lt;h1&gt;Smarte Sockets (Steckdosen)&lt;/h1&gt;
&lt;p&gt;Das nächste intelligente Gerät waren die Smart Sockets. Ich liebe diese Steckdosen, da sie eine Reihe von schönen Funktionen haben. Erstens, da wir in Deutschland keine manuellen Ein-Aus-Schalter in die Steckdosen integriert haben, wie ich aus Großbritannien gewöhnt bin, ist es sehr praktisch, dass diese intelligenten Steckdosen einen Ein-Aus-Schalter haben. Dann muss man beim Herausziehen kaum Kraft aufbringen.&lt;/p&gt;
&lt;p&gt;Die nächste coole Funktion dieser Sockets ist, dass sie per Zeitplan aus und eingeschaltet werden können. Zum Beispiel werden Nachts dann alle Geräte an der Fernsehstation ausgeschaltet, da diese selbst im Standby immer noch viel Strom verbrauchen. Auch die Mikrowelle wird zeigesteuert. Da es sich um eine altes Modell handelt, verbraucht sie viel Energie, selbst wenn sie im Standby ist. Wenn jemand sie wieder einschalten möchte, muss einfach die Taste am Socket gedrückt werden.&lt;/p&gt;
&lt;p&gt;Zu guter Letzt die Waschmaschine. Diese hat jetzt auch eine intelligente Steckdose bekommen. Der Ein-Aus-Schalter ist praktisch, um nicht mit roher Gewalt am Kabel ziehen zu müssen. Es spart Energie, weil es die Maschine vollständig ausschaltet. Wirklich cool wirds jetzt! Ich habe die &quot;Smart Life&quot; App so konfiguriert, dass sie mir eine Benachrichtigung sendet, wenn die Wäsche fertig ist. Das ist möglich, weil der Socket eine Benachrichtigung auslösen kann, wenn eine gewisse Wattzahl erreicht wird. Super praktisch!&lt;/p&gt;
&lt;h1&gt;Intelligentes Garagentor&lt;/h1&gt;
&lt;p&gt;Stell dir vor, du könntest den Garagentor öffnen indem du nur &quot;Hey Siri, Garage&quot; sagst. Nun, das ist bei mir der Fall. Und bis jetzt fühle ich mich wie Batman, wenn er seine Höhle automatisch öffnet, sobald er sich in seinem Batmobil nähert. Also sehr sehr cool. Wie habe ich das gemacht? Als ich das Haus gekauft habe, gab es bereits ein elektrisches Garagentor, das mit einer einfachen Infrarotfernbedienung gesteuert werden konnte. Ja, das ist schön, aber es ist nicht wirklich praktisch, diese Fernbedienung immer bei sich zu haben, und sie kann auch nicht sprachgesteuert werden. Also schrieb ich den Namen des Garagenmotors auf und kaufte bei Amazon ein Smart Garage-Gadget, das mit diesem Motor und der &apos;Smart Life&apos;-App kompatibel ist.&lt;/p&gt;
&lt;p&gt;Die Installation des Gerätes war einfach. Ich habe nun die folgenden Vorteile. Die altmodische Fernbedienung funktioniert immer noch, aber jetzt kann ich die Tür mit meinem Smartphone und der App &apos;Smart Life&apos; oder mit direkt per Siri öffnen und schließen. Außerdem kann ich auf meinem Telefon überprüfen, ob die Garage geöffnet oder geschlossen ist, und ich erhalte einen Alarm, wenn die Tür geöffnet wird. Und wirklich cool, der Motor für die Garage wird Nachts ausgeschaltet. Das spart Kosten und erhöht die Sicherheit.&lt;/p&gt;
&lt;h1&gt;Zeitgesteuerte Thermostate&lt;/h1&gt;
&lt;p&gt;Ich bin sehr zufrieden mit meinen &quot;Smart&quot; Thermostaten von Eqiva Radiator die ich für viele meiner Heizungen nutze. Obwohl ich nicht sicher bin, ob sie unter die Kategorie der Smart Home-Geräte fallen, da sie im Grunde nur über das Display konfigurierbar sind und ich sie derzeit nur zum planmäßigen Heizen und einfachen Ein- und Ausschalten verwende. Wie auch immer, es war sehr einfach sie zu installieren und sie funktionieren ausgezeichnet.&lt;/p&gt;
&lt;h1&gt;Smart Home-Geräte&lt;/h1&gt;
&lt;p&gt;Wenn dir einige der hier erwähnten Gadget gefallen haben, schaue dir doch diese Affiliates an (damit unterstütz du mich auch und ich würde eine kleine Provision erhalten, welche ich direkt in meine Blogpost-Arbeit reinvestieren würde):&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;Intelligentes Garagentor&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;Thermostate&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;Zukünftige Ideen&lt;/h1&gt;
&lt;p&gt;Ich habe das Gefühl, dass ich gerade erst mit meiner kleinen Smart Home-Reise begonnen habe. Bald möchte ich komplexere Technologien wie das Tado Smart Radiator-System ausprobieren. Außerdem denke ich darüber nach, mir meinen eigenen privaten Smart Home Server mit einem PI einzurichten. Ich habe dazu einige interessante Artikel in einer deutschsprachigen Zeitschrift gefunden.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Smart Home-Geräte sind nicht nur Werkzeuge zum Herumspielen. Sie helfen tatsächlich dabei Geld zu sparen und die Lebensqualität verbessern. Wenn du vielleicht daran denkst, einen Blick in die Welt der Smart Home-Geräte zu werfen, empfehle ich dir die WLAN-Smart Bulbs und Smart Sockets, für deren Funktion keine anderen Geräte erforderlich sind! Sei kreativ, wie du sie auf intelligente Art und Weise einsetzen kannst. Und am wichtigsten hab Spaß dabei!&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[ADF App Bauen vom Scratch]]></title><description><![CDATA[Good day Wie im vorangegangen Blog Post erwähnt, arbeite ich an einem spannenenden AI Prototyp welcher ACS Community als Content Managment…]]></description><link>https://martinmueller.dev/ADF-App/</link><guid isPermaLink="false">https://martinmueller.dev/ADF-App/</guid><category><![CDATA[de]]></category><category><![CDATA[alfresco]]></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><category><![CDATA[angular]]></category><category><![CDATA[webapp]]></category><pubDate>Sat, 29 Feb 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/c3cce4d377140aa480a0892d4a64911c/robot.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Good day&lt;/p&gt;
&lt;p&gt;Wie im vorangegangen &lt;a href=&quot;https://martinmueller.dev/Erste-Woche-Object/&quot;&gt;Blog Post&lt;/a&gt; erwähnt, arbeite ich an einem spannenenden AI Prototyp welcher ACS Community als Content Managment System verwendet. Darüber hinaus laufen noch gewisse AI Services welche über die ACS Schnittstelle wie CMIS und REST gewisse AI Aktionen auf ACS durchführen. Leider muss ich hier etwas im unklaren bleiben, um Firmengeheimnisse zu waren. Soviel sei allerdings gesagt &lt;a href=&quot;https://www.object.ch&quot;&gt;OBJECT&lt;/a&gt; und die Partnerfirma planen ein Webinar wo unter anderem auch der hier besprochene Prototyp gezeigt wird. Zurück zum Thema! Für die Webapp haben wir uns für &lt;a href=&quot;https://www.alfresco.com/de/ecm-software/application-development-framework&quot;&gt;ADF&lt;/a&gt; entschieden.&lt;/p&gt;
&lt;p&gt;In den nächsten Kapiteln werde ich erklären wir man ein ADF Webapp Projekt erstellen kann und es nach wünschen zu ändern. Diese sollten sich auch wenig bis garnicht unterscheiden ob man nun mit Windows 10, MacOS oder Linux arbeitet. Ich selber mag alle drei Operation Systeme.&lt;/p&gt;
&lt;h1&gt;Das wird Benötigt&lt;/h1&gt;
&lt;p&gt;Ihr solltet &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; und &lt;a href=&quot;https://yarnpkg.com/lang/en/docs/install/&quot;&gt;YARN&lt;/a&gt; installiert haben. YARN brauchte ich da ich auf einen Windows Laptop arbeite und YARN in der Lage ist die Windows Paths in Unix Paths zu konvertieren. Aufpassen bei Docker! Die Standardinstallation bei Docker erlaubt nur die Verwendung von 2 GB RAM für die Docker Compose Deployments, welches viel zu wenig ist für ACS Community und die anderen Services! Dafür braucht ihr mindestens 10 GB und für ACS Enterprise mindestens 12 GB. Vorzugsweise mehr! Zusätzlich, falls ihr eigene Amps, Jars oder andere Customizations für das ACS Deployment einrichten wollt, empfiehlt es sich Java und Maven zu installieren.&lt;/p&gt;
&lt;h1&gt;Git Repository Vorbereiten&lt;/h1&gt;
&lt;p&gt;Als base für den Prototyp verwende ich das &lt;a href=&quot;https://github.com/Alfresco/alfresco-content-app&quot;&gt;ACA Git Repository&lt;/a&gt;. Zum einen hat es viele &lt;a href=&quot;https://github.com/Alfresco/alfresco-ng2-components&quot;&gt;ADF Component und API Libaries&lt;/a&gt; bereits integriert und zum andern stellt es eine Shell bereit die schon recht umfangreich das ACS Backend verwendet. Darüber hinaus wird es einfach möglich sein, Updates vom ACA repository in meine Webapp einzuspielen. Und ziemlich cool, ich kann direct zurück kontributieren.&lt;/p&gt;
&lt;p&gt;Nun geht es ans Git Repository. Für mich viel die Wahl auf ein privates Git Repository bei uns im &lt;a href=&quot;https://www.object.ch&quot;&gt;OBJECT&lt;/a&gt; GitLab, da es ja eine Vorbereitungsprojekt für ein Webinar werden soll und niemand die Webapp schon vorher sehen darf. In deinem fall kannst du vielleicht ein public Git Repository nehmen. Der weitere Verlauf wird sich dadurch nicht ändern.&lt;/p&gt;
&lt;p&gt;Wie vorhin angesprochen würde ich gerne in der Lage sein Updates vom ACA repository problemlos einzuspielen. Darüber hinaus will ich natürlich soviel es geht vom ACA repository wiederverwenden. Ich habe mich daher für &lt;a href=&quot;https://git-scm.com/docs/git-submodule&quot;&gt;Git&apos;s submodules&lt;/a&gt; entschieden. Damit bin ich dann auch in der Lage zurück zu kontributieren. Ich habe ein Fork vom ACA repo erstellt &lt;a href=&quot;https://github.com/mmuller88/alfresco-content-app&quot;&gt;https://github.com/mmuller88/alfresco-content-app&lt;/a&gt; . Ich rate dir das gleiche zu tun. Dann einfach ins Projektverzeichniss wechseln und den Fork als submodule laden:&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;Eventuell kann auch der folgende Befehl nützlich sein um die Submodules, welches in diesem Fall ja nur ACA ist, zu aktualisieren:&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;Ich brauchte es da ich zu einem Fix Branch gewechselt habe im .gitmodules File.&lt;/p&gt;
&lt;h1&gt;ACA Starten&lt;/h1&gt;
&lt;p&gt;Wenn nun das Webapp Repository soweit konfiguriert wurde, können wir testen ob das Docker Compose Deployment im alfresco-content-app Folder auch startet. In meiner Vorherigen Position als Fullstack Entwickler bei Alfresco hatte ich die Gelegenheit viel mit dem ACA Repository zu arbeiten.&lt;/p&gt;
&lt;p&gt;Zum starten des ACA Deployments sind die folgenden Befehle nötig:&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;Um die nötigen Node Dependencies zu laden.&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;Um die ADF Webapp im dist/app Verzeichniss zu erstellen. Darüber hinaus erstellt der Befehl auch die ADF Extensions mit namen @alfresco/aca-shared und @alfresco/adf-office-services-ext . Als frühen Ausblick sei gesagt, Ziel wird es sein für die eigene ADF Webapp eine eigene Extension zu schreiben. Dies hat praktische Gründe wie der Modularisierung und Distributierung.&lt;/p&gt;
&lt;p&gt;Das start.sh im ACA Verzeichniss ist ein ausgeklügelt Script. Ihr solltet es bevorzugsweise nutzen um das Deployment zu starten. Die einzelnen Parameter lassen sich mit dem -h oder --help Flag erfragen. Für meinen Windows Laptop muss ich dann diese Parameter Konfiguration nutzen:&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;Das -wp Flag wandelt die Linux Dateipfade in Windows Dateipfade um und -hi steht für Host IP und übergibt dem Deployment die IP des Computers. Wenn alles Tutti Frutti ist sollten folgende Adressen erreichbar sein:&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;Zum Zeitpunkt der Artikelerstellung bekomme ich einen komischen Error wegen des GoogleDocs Modules auf meinem Windows PC. Ich bin mir sicher, dass ich diesen nicht auf meinem MacBook bekomme. Ich ignoriere diesen Error getrost. Falls du werter Leser allerdings weist warum, würde ich mich gerne über eine Privatnachricht mit Erklärung freuen.&lt;/p&gt;
&lt;p&gt;Um das Deployment sauber wieder runterzufahren einfach folgenden Befehl benutzen:&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;Das stopp und löscht alle Container die mittels start.sh gestartet wurden. Du musst das Deployment löschen und erneut starten wenn du Änderungen von der webapp im dist/app Folder applyen willst. Alternativ kannst du auch das -aca Flag benutzen welches nur den webapp Container neustartet.&lt;/p&gt;
&lt;h1&gt;Deployment Anpassen&lt;/h1&gt;
&lt;p&gt;Dieser und der nächste Abschnitt ist wohl der schwerste und erfordert viel Geduld. Bisher war es ein leichtes da wir einfach nur bestehenden Code genommen haben, welches bereits von anderen Entwicklern konfiguriert und getestet wurde. Nun müssen wir das allerdings selber machen, denn wir wollen ja in der Lage sein Customizations so wie unsere eigene Extension einzubinden. Also nehmt euch nen Cafe oder wie in meinem Fall nen Tee und ran an den Speck!&lt;/p&gt;
&lt;p&gt;Zum manipulieren des Docker Compose Deployments habe ich alle direkten Dockerbezüglichen Files aus dem ACA Folder in den Projektfolder kopiert. Das beinhaltet zum Beispiel &lt;strong&gt;docker-compose.yaml&lt;/strong&gt;, &lt;strong&gt;start.sh&lt;/strong&gt;, &lt;strong&gt;Dockerfile&lt;/strong&gt; und den &lt;strong&gt;docker&lt;/strong&gt; Folder. Es wäre nun ratsam zu testen ob euer Docker Compose Deployment jetzt immer noch funktioniert. Dafür vielleicht einfach erstmal die ADF Webapp im alfresco-content-app/dist/app folder in den Projekt dist/app Folder kopieren und das Deployment mit start.sh starten. Wie das geht, habe ich ja im vorherigen Kapitel beschrieben.&lt;/p&gt;
&lt;p&gt;Jetzt kommt der wohl schwierigste Part, zumindestns war es für mich so. Ihr müsst nun auch die Angular bezüglichen Files in den Projektfolder kopieren und diese so konfigurieren, dass sie die Componenten aus von alfresco-conten-app/src benutzen. In meiem Fall waren es die folgenden Datein:&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;Ich will hier nichts vormachen, die richtige Einstellung der Konfiguration hat mich tatsächlich zwei Tage gekostet. Als ich nicht mehr weiterkam, suchte ich Rat bei der wundervollen &lt;a href=&quot;https://gitter.im/Alfresco/content-app&quot;&gt;ADF Community in Gitter&lt;/a&gt;. Die Jungs und Mädels verstehen ihr Handwerk. Besonderen Dank an meinen Freund und Exkollegen &lt;a href=&quot;https://twitter.com/pionnegru&quot;&gt;Bogdan&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Jetzt ist es an der Zeit den dist/app folder selber von Angular compilieren zu lassen, anstelle es nur aus dem aca projekt zu kopieren. Wenn du es hinbekommen hast, dass das Docker Compose Deployment erfolgreich mit der im Parentfolder compilierten Webapp im dist folder, kann endlich das Customizing beginnen :) !&lt;/p&gt;
&lt;h1&gt;Extension Erstellen&lt;/h1&gt;
&lt;p&gt;Wohoo! Du hast es tatsächlich bis hierher geschafft. Nun wird es um so mehr Angular lastig. Um eine neue Extension zu bauen empfiehlt sich der Befehl:&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;Ich würde sehr empfehlen ein -ext an den Namen der Extension zu fügen, um es unterscheidbarer von der Webapp zu machen. In meinem Projekt haben sie die gleichen Namen mit Ausnahme, dass ich der Extension noch -ext angefügt habe. Was man nun mit der Extension macht ist total offen und es gibt viele tolle Angular Tutorials, Seiten oder Foren die einen Helfen die gewünschten Änderungen zu erreichen.&lt;/p&gt;
&lt;p&gt;Willst du zwischendurch oder am Ende deiner Änderungen die Webapp testen, musst du einfach die ADF Webapp compilieren und das Docker Compose Deployment starten. Dies schaut ähnlich auch wie im &lt;strong&gt;Abschnit ACA Starten&lt;/strong&gt; erklärt mit den folgenden Befehlen:&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;Bitte nicht vergessen das -wp ist Windows spezifisch. Wenn ihr MacOS oder Linux benutzt braucht ihr dieses Flag nicht. Ihr würdet dann wahrscheinlich nichtmal -hi IP benötigen.&lt;/p&gt;
&lt;h1&gt;Neues ACA Update Verfügbar&lt;/h1&gt;
&lt;p&gt;Als sich das &lt;a href=&quot;https://github.com/Alfresco/alfresco-content-app&quot;&gt;ACA Git Repository&lt;/a&gt; mit unglaublich schneller Geschwindigkeit weiterentwickelt, stellt sich die Frage wie wir diese Updates in wenigen Schritten in unsere ADF Webapp integrieren können. Ich brauchte dies zwar bisher nicht machen für meinen ADF AI Prototypen, aber grundlegend seien diese Schritte genannnt:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Es muss das alfresco-content-app Git Submodule geupdated werden.&lt;/li&gt;
&lt;li&gt;Die Versionen in package.json im Projetfolder müssen mit denen im alfresco-content-app/package.json synchronisiert werden&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Wow überlegt mal was wir hier geschafft haben. Wir haben tatsächlich unsere eigene ADF Webapp geschrieben welche auf ACA basiert und jederzeit einfach upgedatet werden kann! Dafür mussten wir zuerst ein neues Git Repo erstellen. Dann das ACA Projekt als Submodul einbinden. Unmittelbar danach testeten wir das Docker Compose Deployment in ACA. Dann haben wir das Repo so umgebaut, dass wir unsere eigene Angular Extension in die ADF Webapp integriert haben. Das wars! Ich hoffe ihr hattet Spaß und war der Artikel war hilfreich.&lt;/p&gt;
&lt;h1&gt;Kudos&lt;/h1&gt;
&lt;p&gt;Für &lt;a href=&quot;https://twitter.com/freshwebs&quot;&gt;Eddie May&lt;/a&gt; der brand neue Digital Community Manager von Alfresco für das Berichtigen meiner englischen Übersetzung und das Angebot mir auch in zukünftigen Posts Feedback zu geben :).&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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/c3cce4d377140aa480a0892d4a64911c/robot.png</featuredImage><media:content url="https://martinmueller.dev/static/c3cce4d377140aa480a0892d4a64911c/robot.png" medium="image"/></item><item><title><![CDATA[Meine Erste aufregende Woche bei OBJECT]]></title><description><![CDATA[Moin. In diesem Artikel fasse ich kurz die erste Woche bei OBJECT zusammen. Für mich selber bietet dieses einige Vorteile. Zum einen ich übe…]]></description><link>https://martinmueller.dev/Erste-Woche-Object/</link><guid isPermaLink="false">https://martinmueller.dev/Erste-Woche-Object/</guid><category><![CDATA[de]]></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><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;Moin.&lt;/p&gt;
&lt;p&gt;In diesem Artikel fasse ich kurz die erste Woche bei &lt;a href=&quot;https://www.object.ch&quot;&gt;OBJECT&lt;/a&gt; zusammen. Für mich selber bietet dieses einige Vorteile. Zum einen ich übe regelmäßiges Artikelschreiben und zum Anderen dient es als Reflexion über die vorangegangen Tage. Darüber hinaus fällt es einigen meiner Verwandten und Freunden schwer zu verstehen wie mein Traumjob als Software Engineer so aussieht. Diese Art von Blogpost können dabei helfen es besser zu verstehen. Hoffe ich zumindest.&lt;/p&gt;
&lt;h1&gt;Tag 1 Onboarding&lt;/h1&gt;
&lt;p&gt;Ursprünglich war es geplant, dass ich ich nach Zürich kommen sollte zum Onboarding. Kurz gesagt als Onboarding bezeichnet man in der Regel der Prozess bei dem neu angestellte Mitarbeiter mit der Hardware und den verschiedenen Softwaresystemen vertraut gemacht werden, sowie die zukünftigen Aufgabenbereiche. Allerdings war meine Frau zu dem Zeitpunkt schwanger und ich wollte sie von daher ungern verlassen.&lt;/p&gt;
&lt;p&gt;Um so überraschter und sehr glücklich war ich, als OBJECT mir anbot das Onboarding in Hamburg zu machen. Ich liebe Hamburg, denn es is eine schöne Stadt am Wasser. Im Titelbild ist die Kirche St. Jacobi von Hamburg zu sehen, welche mir gleich aufgefallen war auf dem weg zum Onboarding. Drei spannende Hauptaufgaben wurden mir zugeteilt. Über diese darf und möchte ich nur in sehr groben Details schreiben.&lt;/p&gt;
&lt;p&gt;Die erste Aufgabe ist, dass ich ein eigenes Projekt zusammen mit einem anderen Partner übernehmen und leiten soll. Dieses Projekt befasst sich mit einem sehr spannenden Alfresco Deployment. In diesem Deployment sollen ACS (Alfresco Content Service) und APS (Alfresco Process Service) zusammen laufen. Das ist super spannend das ich Alfresco&apos;s ECM und BPM Produkte miteinander kombinieren darf.&lt;/p&gt;
&lt;p&gt;In dem zweiten Projekt geht es um eine Entwicklung eines Prototypen für die Auffindung von sensiblen Daten. Dafür würden wir auch gerne eine schicke ADF app benutzen. In diesem Projekt werde ich meine bisher erlangten Skills mit Docker und ADF voll ausspielen können.&lt;/p&gt;
&lt;p&gt;Im dritten und wohl für mich spannensten Projekt geht es darum, dass OBJECT gerne eine stärker Sozial Media Präsenz hätte. Das ginge von Platformen wie Xing, LinkedIN zu YouTube Videos. Auch hier habe ich großes Interesse mein bisher erlangtes Wissen über Alfresco zielführend einzusetzen und meine bisher bescheidenen aber existierenden Sozial Medial Skills auszubauen.&lt;/p&gt;
&lt;p&gt;Zusammenfassend für diesen Tag kann ich sagen, dass der Tag sehr anstrengend, aber auch sehr produktiv und toll, war. Ich bin sehr happy das OBJECT großes mit mir vorhat.&lt;/p&gt;
&lt;h1&gt;Tag 2 Project Einführung&lt;/h1&gt;
&lt;p&gt;Mein toller brasilianische Kollege, auch von mir Amigo genannt, hat sich die Zeit genommen und mir das aktuelle ACS 5.2. Deployment gezeigt. Ich habe alle Details verschlungen und ihm viele Fragen gestellt. Wir benötigten etwa zwei Stunden. Am meisten beeindruckt hat mich der Entwurfsprozess für dieses Deployment. Es waren einige Entwurfsdiagramme nötig, bis sich auf das finale Diagram entschieden wurde. Bereits jetzt habe ich schon ein paar interessante Ideen wie man das Deployment besser gestalten könnte in Punkto einfacher Wartbarkeit, Sicherheit, verminderter Fehleranfälligkeit und Verlässlichkeit.&lt;/p&gt;
&lt;h1&gt;Tag 3 Developer Meeting&lt;/h1&gt;
&lt;p&gt;Am Mittwoch und somit der dritte Tag hatten wir ein zirka einstündiges Meeting mit allen Developern bei OBJECT. In dieser Runde stellte sich jeder kurz vor und erklärte mir an welchen spannenden Aufgaben sie arbeiten. Um diese Flut an Informationen besser zu verarbeiten, entschloss ich mich diese in kurzen Stichpunkten in mein Notizblock niederzuschreiben. Die Kennenlernrunde war sehr toll und ich wage mich zu behaupten, dass ich einen guten ersten Eindruck von mir hinterlassen habe. Ich hoffe schon bald öfter mit dem einen oder anderen Kollegen zusammenzuarbeiten zu können, da ich das Gefühl habe noch viel von ihnen lernen zu können.&lt;/p&gt;
&lt;p&gt;Den Rest des Tages verbrachte ich damit, mich weiter mit dem, im vorherigen Kapitel erwähnten, Deployment zu befassen. Auch habe ich einen Verbesserungsvorschlag ausgearbeitet welchen ich bald meinen Kollegen und unserem Partner vorschlagen möchte.&lt;/p&gt;
&lt;h1&gt;Tag 4 Inspirierendes Konversation&lt;/h1&gt;
&lt;p&gt;Heute am Donnerstag hatte ich ein super interessantes und inspirierendes Gespräch mit einem Partner von uns. Dieser ist im Bereich AI (Artificial Inteligence) tätig und hat eine eigene Firma gegründet. Alfresco&apos;s Content Managment System ist dabei nur eine Plattform von vielen wo mittels AI wertvolle Informationen extrahiert werden können. Ich war so erstaunt wie dieser Gründer so mit voller Begeisterung über das entwickelte Produkt gesprochen hat.&lt;/p&gt;
&lt;p&gt;Mein Ziel ist es nun in den nächsten Wochen einen auf ADF basierenden Prototypen zu entwickeln, welche die zuvor erwähnten AI Fähigkeiten demonstrieren kann. Sehr gerne arbeite ich mit ADF. Wie schon im &lt;a href=&quot;https://martinmueller.dev/Object-CH/&quot;&gt;vorherigen Blog Post&lt;/a&gt; erwähnt liebe ich dieses Framework. Meine Idee ist es &lt;a href=&quot;https://github.com/Alfresco/alfresco-content-app&quot;&gt;Alfresco&apos;s ADF App mit namen ACA&lt;/a&gt; als Grundlage für den Prototypen zu gehört. Vielleicht wäre es eine coole Idee auch einen Artikel über diese App zu schreiben.&lt;/p&gt;
&lt;h1&gt;Tag 5 AI Magie&lt;/h1&gt;
&lt;p&gt;Als ich angefangen habe diesen Artikel zu schreiben, habe ich mit sicherheit nichtmal ansatzweise daran gedacht das AI so ein wichtiger Inhalt dieses Post wird. Ich bin sehr AI interessiert und heute am Freitag, habe ich eine coole Life Demonstration über ein AI System bekommen, welches Alfresco&apos;s Content Management System als Datenquelle verwendet um extrem interessante Informationen zu extrahieren. Auch warnt das System den Nutzer gegebenfalls, wenn etwas misstrauisches passiert.&lt;/p&gt;
&lt;p&gt;Sehr interessant fand ich, dass schon eine einfache ACS Community version ohne jegliche Customization ausreichte. Diese Demonstration hat mir ein gutes Bild verschafft wie die ADF App aussehen soll. Am Montag werde ich anfangen kleine Skizzen von dem Prototypen anzufertigen.&lt;/p&gt;
&lt;h1&gt;Zusammenfassung&lt;/h1&gt;
&lt;p&gt;Die erste Woche war intensiv aufgrund der vielen neuen Informationen. Positiv überrascht war ich, dass schon recht viele Kollegen auf die von mir angebotene Hilfe zurückgegriffen haben. Ebenso schaue ich mit voller Ehrgeiz und Begeisterung in die Zukunft von mir zusammen mit OBJECT.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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[Von Alfresco zu OBJECT]]></title><description><![CDATA[Hi werter Leser. Mit voller Freude darf ich verkünden, dass ich am 14. Februar zu OBJECT wechsle. Diese ist eine Partnerfirma von meiner…]]></description><link>https://martinmueller.dev/Object-CH/</link><guid isPermaLink="false">https://martinmueller.dev/Object-CH/</guid><category><![CDATA[de]]></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;Hi werter Leser.&lt;/p&gt;
&lt;p&gt;Mit voller Freude darf ich verkünden, dass ich am 14. Februar zu &lt;a href=&quot;https://www.object.ch&quot;&gt;OBJECT&lt;/a&gt; wechsle. Diese ist eine Partnerfirma von meiner jetzigen Firma &lt;a href=&quot;https://www.alfresco.com&quot;&gt;Alfresco&lt;/a&gt;. OBJECT agiert hauptsächlich im Deutschen und Schweizerischen ECM (Enterprise Content Management) Markt. Nachfolgend liste ich meine Beweggründe auf und am Schluss erkläre ich meine Zukunftsvisionen von OBJECT und Alfresco für das Jahr 2022.&lt;/p&gt;
&lt;h1&gt;Gründe für den Wechsel&lt;/h1&gt;
&lt;p&gt;Einer meiner grössten Beweggründe ist das mir die Alfresco Produkte sehr gefallen. Alfresco Content System (ACS) ist ein geniales und ausgeklügeltes auf der Java VM basierendes Content Management System. Auch wenn ich bisher kaum die Möglichkeit hatte mit Alfresco Process Service (APS) zu arbeiten, erkenne ich wie toll auch dieses Produkt ist und möchte auch gerne in Zukunft damit befassen. Last but not least Alfresco Developer Framework (ADF). Ich finde die neuen, auf Angular basierenden, Weboberflächen sehr schön und genial für das Frontend. Vor allem die einfache Benutzung der Graphischen Oberfläche sowie die umfangreiche Sammlung an vorgefertigten Components, wie z.B. der &lt;a href=&quot;https://www.alfresco.com/abn/adf/docs/content-services/components/document-list.component&quot;&gt;Document List&lt;/a&gt;, haben es mir angetan. 2019 hatte ich die Gelegenheit den ADF Teams mit Alfresco Backend Knowhow zu helfen und konnte dabei auch vieles über ADF lernen, wofür ich sehr dankbar bin.&lt;/p&gt;
&lt;p&gt;Der Wechsel zu OBJECT sollte es mir auch ermöglichen näher am Kunden zu sein. Ich möchte Lösungen für und mit dem Kunden entwickeln. Ich bin davon überzeugt das Alfresco hervorragende Lösungen im ECM und BPM Bereich bieten. In Zusammenarbeit mit dem Kunden werde ich dabei helfen die ideale Lösung zu finden. Ich würde dabei auch nicht zurückscheuen neben Alfresco auch andere Software Produkte für Lösungen oder Teillösungen in Betracht zu ziehen. Tatsächlich liebe ich es neue sowie andere Software Technologien kennen zu lernen.&lt;/p&gt;
&lt;p&gt;Auch habe ich in den letzten Jahren die Möglichkeiten der Cloud für mich entdeckt und war einfach nur überwältigt. Mit solch einer Einfachheit mit der sich Infrastruktur wie virtuelle Server oder Speicher bereitstellen lassen und kostengünstig zu betreiben, sucht seines gleichen. Das Agieren in der Cloud hat mir soviel Spass gemacht, dass ich mich dazu entschlossen hatte, AWS Zertifikate zu machen. Neben vorangegangen anderen bestandenen Zertifikaten errang ich im Juli 2019 das &quot;AWS Solution Architekt Professional&quot; Zertifikat, worauf ich sehr stolz bin. Wenn du gerne mehr wissen möchtest über das Zertifikat und die Vorbereitungen dafür, schau bei meinem Blogpost &lt;a href=&quot;https://martinmueller.dev/aws-architect-professional-2019-preparation&quot;&gt;SAP-C01&lt;/a&gt; vorbei. Von daher würde ich mich freuen, wenn ich die Benutzung der Cloud im deutschsprachigen Raum vorantreiben kann.&lt;/p&gt;
&lt;p&gt;Auch interessiere ich mich sehr für neue Technologien der Informatik wie Docker und Kubernetes. Das arbeiten mit Docker finde ich deshalb so schön, da man quasi immer wieder saubere Umgebungen bereitstellen und ggf. konfigurieren kann und das mit nur wenig Zeilen Code. Auch ist es einfach unvergleichlich um wieviel einfacher die Entwicklung mit Alfresco Produkten wird, wenn diese in Containern bereits definiert sind. Ebenfalls bietet Alfresco Referenz Images z.B. &lt;a href=&quot;https://github.com/Alfresco/acs-packaging/blob/master/docker-alfresco/Dockerfile&quot;&gt;acs-packaging&lt;/a&gt; sowie Deployments z.B. &lt;a href=&quot;https://github.com/Alfresco/acs-deployment/blob/master/docker-compose/docker-compose.yml&quot;&gt;acs-deployment&lt;/a&gt; an, die einfach verwendbar sowie customizable sind. Auch möchte ich an dieser Stelle Kubernetes nicht auslassen. Kubernetes hat zwar eine steile Lernkurve, aber eingesetzt in der Produktion ist es einfach unschlagbar. Ebenfalls besitzt Alfresco auch hier ein Referenz Deployment &lt;a href=&quot;https://github.com/Alfresco/alfresco-dbp-deployment&quot;&gt;alfresco-dbp-deployment&lt;/a&gt;. Gerne würde ich mich freuen diese Technologien stärker im deutschsprachigem Raum weiter voranzutreiben.&lt;/p&gt;
&lt;p&gt;Zu guter Letzt. Der Bewerbungsprozess mit OBJECT war eine wunderschöne Erfahrung und hat schon sehr herausgestochen zu all meinen Bewerbungen davor. Die Mitarbeiter bei OBJECT machen einen sehr glücklichen und aufgeschlossenen Eindruck. Auch finde ich die Home Office Kultur von OBJECT toll und zeitgemäss. Das ist die ideale Umgebung um mich weiterzuentwickeln.&lt;/p&gt;
&lt;p&gt;Im nächsten Abschnitt würde ich gerne einen Ausblick über OBJECT zusammen mit Alfresco für das Jahr 2022 geben.&lt;/p&gt;
&lt;h1&gt;Ausblick 2022&lt;/h1&gt;
&lt;p&gt;In dem letzten Jahr bei Alfresco, konnte ich den Cloud Trend beobachten sowie selber daran mitwirken. Ich weiss das dieser noch stärker ausgebaut wird. Alfresco bietet bereits ein starkes PaaS (Program as a Service) Angebot und wird dieses in Zukunft noch weiter ausbauen. Realistisch gesehen glaube ich das dieses Angebot im deutschsprachigen Raum bis 2022 noch nicht oder nur wenig genutzt wird, da Länder wie Deutschland sich sehr vorsichtig und somit auch langsam in der Cloud Welt bewegen.&lt;/p&gt;
&lt;p&gt;Auch wenn bis 2022 der deutschsprachige Raum das Alfresco&apos;s PaaS Angebot kaum nutzen wird, werden wir einen starken Gang in Richtung Cloud erleben, bezüglich der Alfresco Produkte. Schon heute lassen sich viele Kosten sparen mit der Verwendung der Cloud als Storage z.B. macht es der S3 oder Azure Connector von ACS einfach, die BLOB Storages der jeweiligen Cloud provider zu verwenden. OBJECT kann dabei als vertrauenswürdiger Partner Rat und Tat leisten.&lt;/p&gt;
&lt;p&gt;Viele Alfresco Kunden benutzten bereits die schicken mit ADF erstellten Webapplikationen und bis 2022 werden es garantiert mehr. OBJECT sehe ich in der perfekten Lage gemeinsam mit dem Kunden angepasste ADF Apps zu entwickeln.&lt;/p&gt;
&lt;p&gt;An die tollen Leser dieses Artikels sei gesagt, dass Feedback jeglicher Art gerne gesehen ist. In Zukunft werde ich versuchen hier eine Diskussionsfunktion einzubauen. Bis dahin sendet mir doch bitte direkten Feedback über meine Sozial Media accounts wie &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; oder &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Vielen Dank :).&lt;/p&gt;
&lt;p&gt;Ich liebe es an Content Management Open Source Projekte zu arbeiten. Vieles kannst du bereits frei nutzen auf &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . Wenn du meine dortige Arbeit sowie meine Blog Posts toll findest, denke doch bitte darüber nach, mich zu unterstützen und ein Patreon zu werden:&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;Werde ein 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></channel></rss>