Skip to content

Instantly share code, notes, and snippets.

@azell
Created June 16, 2026 06:01
Show Gist options
  • Select an option

  • Save azell/49e748c2a2e2073887648773e67ba4b7 to your computer and use it in GitHub Desktop.

Select an option

Save azell/49e748c2a2e2073887648773e67ba4b7 to your computer and use it in GitHub Desktop.
mermaid-img.svg
Display the source blob
Display the rendered blob
Raw
<svg width="680" viewBox="0 0 680 820" xmlns="http://www.w3.org/2000/svg" role="img">
<title>CTA After Architecture v5</title>
<desc>Web and mobile clients call the CTA Service. CTA Service calls Apollo GraphQL Router, which routes to the CTA Content Orchestrator. The orchestrator has a DynamoDB store, exposes a personalization API to content services, fans out via the router to 4 content services, and publishes events to Kafka which Databricks consumes for analytics and ML.</desc>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</marker>
<style>
text { font-family: Arial, Helvetica, sans-serif; fill: #1a1a1a; }
.th { font-size: 14px; font-weight: 600; }
.ts { font-size: 12px; font-weight: 400; fill: #444; }
.c-gray rect { fill: #F1EFE8; stroke: #5F5E5A; }
.c-teal rect { fill: #E1F5EE; stroke: #0F6E56; }
.c-teal text { fill: #085041; }
.c-purple rect { fill: #EEEDFE; stroke: #534AB7; }
.c-purple text { fill: #26215C; }
.c-amber rect { fill: #FAEEDA; stroke: #854F0B; }
.c-amber text { fill: #412402; }
.c-blue rect { fill: #E6F1FB; stroke: #185FA5; }
.c-blue text { fill: #042C53; }
.c-coral rect { fill: #FAECE7; stroke: #993C1D; }
.c-coral text { fill: #4A1B0C; }
.c-green rect { fill: #EAF3DE; stroke: #3B6D11; }
.c-green text { fill: #173404; }
.arr { fill: none; stroke: #888; stroke-width: 1; marker-end: url(#arrow); }
</style>
</defs>
<!-- Background -->
<rect width="680" height="820" fill="#ffffff"/>
<!-- ── Clients ── -->
<g class="c-gray">
<rect x="130" y="20" width="120" height="44" rx="8" stroke-width="0.5"/>
<text class="th" x="190" y="42" text-anchor="middle" dominant-baseline="central">Web client</text>
</g>
<g class="c-gray">
<rect x="310" y="20" width="120" height="44" rx="8" stroke-width="0.5"/>
<text class="th" x="370" y="42" text-anchor="middle" dominant-baseline="central">Mobile client</text>
</g>
<!-- Clients → CTA Service -->
<line x1="210" y1="64" x2="255" y2="114" class="arr" marker-end="url(#arrow)"/>
<line x1="370" y1="64" x2="305" y2="114" class="arr" marker-end="url(#arrow)"/>
<!-- ── CTA Service ── -->
<g class="c-teal">
<rect x="120" y="114" width="320" height="56" rx="8" stroke-width="0.5"/>
<text class="th" x="280" y="136" text-anchor="middle" dominant-baseline="central">CTA service</text>
<text class="ts" x="280" y="156" text-anchor="middle" dominant-baseline="central">4,000 req/s · 250 ms budget · direct from clients</text>
</g>
<!-- CTA Service → Router -->
<line x1="280" y1="170" x2="280" y2="216" class="arr" marker-end="url(#arrow)"/>
<!-- ── Apollo GraphQL Router ── -->
<g class="c-purple">
<rect x="140" y="216" width="280" height="56" rx="8" stroke-width="0.5"/>
<text class="th" x="280" y="238" text-anchor="middle" dominant-baseline="central">Apollo GraphQL router</text>
<text class="ts" x="280" y="258" text-anchor="middle" dominant-baseline="central">Routes requests — used at both layers</text>
</g>
<!-- Router → Orchestrator -->
<line x1="280" y1="272" x2="280" y2="318" class="arr" marker-end="url(#arrow)"/>
<!-- ── CTA Content Orchestrator ── -->
<g class="c-amber">
<rect x="120" y="318" width="320" height="56" rx="8" stroke-width="0.5"/>
<text class="th" x="280" y="340" text-anchor="middle" dominant-baseline="central">CTA content orchestrator</text>
<text class="ts" x="280" y="360" text-anchor="middle" dominant-baseline="central">Aggregates per-user personalization · exposes API</text>
</g>
<!-- Orchestrator → DynamoDB (left) -->
<line x1="120" y1="346" x2="114" y2="346" class="arr" marker-end="url(#arrow)"/>
<g class="c-blue">
<rect x="14" y="322" width="100" height="48" rx="8" stroke-width="0.5"/>
<text class="th" x="64" y="340" text-anchor="middle" dominant-baseline="central">DynamoDB</text>
<text class="ts" x="64" y="358" text-anchor="middle" dominant-baseline="central">Personalization</text>
</g>
<!-- Orchestrator → Kafka (right, L-shaped dashed) -->
<path d="M440 346 L580 346 L580 436" fill="none" stroke="#888" stroke-width="1" stroke-dasharray="5 3" marker-end="url(#arrow)"/>
<text class="ts" x="496" y="338" text-anchor="middle">publishes</text>
<!-- ── Kafka ── -->
<g class="c-green">
<rect x="520" y="436" width="120" height="56" rx="8" stroke-width="0.5"/>
<text class="th" x="580" y="458" text-anchor="middle" dominant-baseline="central">Kafka</text>
<text class="ts" x="580" y="476" text-anchor="middle" dominant-baseline="central">Event stream</text>
</g>
<!-- Kafka → Databricks -->
<line x1="580" y1="492" x2="580" y2="546" class="arr" marker-end="url(#arrow)"/>
<!-- ── Databricks ── -->
<g class="c-green">
<rect x="510" y="546" width="140" height="56" rx="8" stroke-width="0.5"/>
<text class="th" x="580" y="568" text-anchor="middle" dominant-baseline="central">Databricks</text>
<text class="ts" x="580" y="586" text-anchor="middle" dominant-baseline="central">Analytics &amp; ML</text>
</g>
<!-- Orchestrator → Router loop back -->
<path d="M420 330 L448 330 L448 238 L422 238" fill="none" stroke="#888" stroke-width="1" stroke-dasharray="5 3" marker-end="url(#arrow)"/>
<text class="ts" x="452" y="290" text-anchor="start">via router</text>
<!-- Fan-out label -->
<text class="ts" x="220" y="410" text-anchor="middle">Synchronous HTTP/gRPC calls</text>
<!-- Router fan-out lines -->
<line x1="195" y1="372" x2="80" y2="460" class="arr" marker-end="url(#arrow)"/>
<line x1="245" y1="372" x2="190" y2="460" class="arr" marker-end="url(#arrow)"/>
<line x1="315" y1="372" x2="300" y2="460" class="arr" marker-end="url(#arrow)"/>
<line x1="355" y1="372" x2="410" y2="460" class="arr" marker-end="url(#arrow)"/>
<!-- ── Content Services ── -->
<g class="c-coral">
<rect x="30" y="460" width="100" height="56" rx="8" stroke-width="0.5"/>
<text class="th" x="80" y="482" text-anchor="middle" dominant-baseline="central">Promotions</text>
<text class="ts" x="80" y="500" text-anchor="middle" dominant-baseline="central">CTA content</text>
</g>
<g class="c-coral">
<rect x="140" y="460" width="100" height="56" rx="8" stroke-width="0.5"/>
<text class="th" x="190" y="482" text-anchor="middle" dominant-baseline="central">Recs</text>
<text class="ts" x="190" y="500" text-anchor="middle" dominant-baseline="central">CTA content</text>
</g>
<g class="c-coral">
<rect x="250" y="460" width="100" height="56" rx="8" stroke-width="0.5"/>
<text class="th" x="300" y="482" text-anchor="middle" dominant-baseline="central">Learning</text>
<text class="ts" x="300" y="500" text-anchor="middle" dominant-baseline="central">CTA content</text>
</g>
<g class="c-coral">
<rect x="360" y="460" width="100" height="56" rx="8" stroke-width="0.5"/>
<text class="th" x="410" y="482" text-anchor="middle" dominant-baseline="central">Onboarding</text>
<text class="ts" x="410" y="500" text-anchor="middle" dominant-baseline="central">CTA content</text>
</g>
<!-- Content services → personalization API -->
<path d="M30 488 L16 488 L16 346 L14 346" fill="none" stroke="#888" stroke-width="1" stroke-dasharray="4 3" marker-end="url(#arrow)"/>
<text class="ts" x="8" y="434" text-anchor="middle" transform="rotate(-90 8 434)">personalization API</text>
<!-- Content services → data stores -->
<line x1="80" y1="516" x2="80" y2="634" class="arr" marker-end="url(#arrow)"/>
<line x1="190" y1="516" x2="190" y2="634" class="arr" marker-end="url(#arrow)"/>
<line x1="300" y1="516" x2="300" y2="634" class="arr" marker-end="url(#arrow)"/>
<line x1="410" y1="516" x2="410" y2="634" class="arr" marker-end="url(#arrow)"/>
<!-- ── Data stores ── -->
<g class="c-blue">
<rect x="28" y="634" width="104" height="48" rx="8" stroke-width="0.5"/>
<text class="th" x="80" y="652" text-anchor="middle" dominant-baseline="central">Postgres</text>
<text class="ts" x="80" y="670" text-anchor="middle" dominant-baseline="central">Promotions DB</text>
</g>
<g class="c-blue">
<rect x="138" y="634" width="104" height="48" rx="8" stroke-width="0.5"/>
<text class="th" x="190" y="652" text-anchor="middle" dominant-baseline="central">DynamoDB</text>
<text class="ts" x="190" y="670" text-anchor="middle" dominant-baseline="central">Recs DB</text>
</g>
<g class="c-blue">
<rect x="248" y="634" width="104" height="48" rx="8" stroke-width="0.5"/>
<text class="th" x="300" y="652" text-anchor="middle" dominant-baseline="central">Postgres</text>
<text class="ts" x="300" y="670" text-anchor="middle" dominant-baseline="central">Learning DB</text>
</g>
<g class="c-blue">
<rect x="358" y="634" width="104" height="48" rx="8" stroke-width="0.5"/>
<text class="th" x="410" y="652" text-anchor="middle" dominant-baseline="central">DynamoDB</text>
<text class="ts" x="410" y="670" text-anchor="middle" dominant-baseline="central">Onboarding DB</text>
</g>
<!-- Legend -->
<rect x="30" y="722" width="12" height="12" rx="2" fill="#F1EFE8" stroke="#5F5E5A"/>
<text class="ts" x="48" y="733">Clients</text>
<rect x="110" y="722" width="12" height="12" rx="2" fill="#E1F5EE" stroke="#0F6E56"/>
<text class="ts" x="128" y="733">CTA orchestration</text>
<rect x="258" y="722" width="12" height="12" rx="2" fill="#EEEDFE" stroke="#534AB7"/>
<text class="ts" x="276" y="733">Gateway / routing</text>
<rect x="398" y="722" width="12" height="12" rx="2" fill="#FAEEDA" stroke="#854F0B"/>
<text class="ts" x="416" y="733">Orchestrator</text>
<rect x="30" y="746" width="12" height="12" rx="2" fill="#EAF3DE" stroke="#3B6D11"/>
<text class="ts" x="48" y="757">Kafka / Databricks</text>
<rect x="178" y="746" width="12" height="12" rx="2" fill="#FAECE7" stroke="#993C1D"/>
<text class="ts" x="196" y="757">Content services</text>
<rect x="328" y="746" width="12" height="12" rx="2" fill="#E6F1FB" stroke="#185FA5"/>
<text class="ts" x="346" y="757">Data stores</text>
</svg>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment