feat(projects): add architecture diagrams, align project texts

Add diagrams to three projects. A tap opens them full size.
Align en/de texts: no versions, Gitea not GitHub, Portainer, home
server + VPS. Make To Be Played the featured project.
Remove the Hostinger logo image.
This commit is contained in:
lobo committed 2026-10-14 08:18:18 +02:00
1 parent 449e2d430a
commit 93e9c59436
11 files changed
+247 -50

No files matched your search

@@ -0,0 +1,72 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 630" width="1200" height="630" role="img" aria-labelledby="title desc">
<title id="title">To Be Played</title>
<desc id="desc">Architecture of To Be Played: a React frontend talks to an Auth service that signs tokens and a Core service that verifies them. Both use PostgreSQL, Core also calls the Steam API and IGDB.</desc>
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#1e2530"/>
<stop offset="100%" stop-color="#15181d"/>
</linearGradient>
<linearGradient id="accent" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#26c6da"/>
<stop offset="100%" stop-color="#ffa726"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#4a5563"/>
</marker>
<marker id="arrowCyan" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#26c6da"/>
</marker>
</defs>
<style>
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; }
.sans { font-family: Roboto, Arial, sans-serif; }
.lbl { fill: #8b97a6; font-size: 17px; letter-spacing: .04em; }
.chip { fill: #cdd6e0; font-size: 19px; }
.cap { fill: #6c7887; font-size: 15px; letter-spacing: .18em; }
.name { fill: #cdd6e0; font-size: 22px; font-weight: 600; }
.sub { fill: #8b97a6; font-size: 16px; }
.arr { fill: #8b97a6; font-size: 15px; }
</style>
<rect width="1200" height="630" fill="url(#bg)"/>
<rect x="0" y="0" width="1200" height="4" fill="url(#accent)"/>
<text x="64" y="72" class="mono" fill="#26c6da" font-size="26" font-weight="600">to-be-played</text>
<text x="64" y="102" class="sans lbl">three services, one login</text>
<rect x="48" y="240" width="196" height="110" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="68" y="274" class="sans name">React Frontend</text>
<text x="68" y="300" class="sans sub">browser</text>
<rect x="350" y="150" width="310" height="120" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="370" y="184" class="sans name">Auth service</text>
<text x="370" y="210" class="sans sub">signs tokens, Ed25519 private key</text>
<text x="370" y="232" class="sans sub">HttpOnly cookies</text>
<rect x="350" y="290" width="310" height="220" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="370" y="324" class="sans name">Core service</text>
<text x="370" y="350" class="sans sub">library, stats, suggestions</text>
<text x="370" y="372" class="sans sub">verifies tokens, public key only</text>
<rect x="740" y="150" width="180" height="230" rx="14" fill="#1a222c" stroke="#2f3a47"/>
<text x="760" y="178" class="sans cap" text-anchor="start">POSTGRESQL</text>
<rect x="760" y="192" width="140" height="56" rx="10" fill="#243040" stroke="#33475c"/>
<text x="830" y="227" class="mono chip" text-anchor="middle">auth db</text>
<rect x="760" y="302" width="140" height="56" rx="10" fill="#243040" stroke="#33475c"/>
<text x="830" y="337" class="mono chip" text-anchor="middle">core db</text>
<text x="1000" y="372" class="sans cap" text-anchor="start">EXTERNAL</text>
<rect x="1000" y="395" width="152" height="50" rx="10" fill="#212a35" stroke="#2f3a47" stroke-dasharray="4 4"/>
<text x="1076" y="427" class="sans chip" text-anchor="middle">Steam API</text>
<rect x="1000" y="460" width="152" height="50" rx="10" fill="#212a35" stroke="#2f3a47" stroke-dasharray="4 4"/>
<text x="1076" y="492" class="sans chip" text-anchor="middle">IGDB</text>
<path d="M 252 258 H 342" stroke="#4a5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
<text x="297" y="248" class="sans arr" text-anchor="middle">login</text>
<path d="M 252 330 H 342" stroke="#4a5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
<text x="297" y="320" class="sans arr" text-anchor="middle">API, cookie</text>
<path d="M 668 220 H 752" stroke="#26c6da" stroke-width="2" fill="none" marker-end="url(#arrowCyan)"/>
<path d="M 668 330 H 752" stroke="#26c6da" stroke-width="2" fill="none" marker-end="url(#arrowCyan)"/>
<path d="M 668 420 H 992" stroke="#4a5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
<text x="830" y="410" class="sans arr" text-anchor="middle">sync</text>
<path d="M 668 485 H 992" stroke="#4a5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
<text x="830" y="475" class="sans arr" text-anchor="middle">time to beat</text>
<line x1="64" y1="566" x2="1136" y2="566" stroke="#2a333e"/>
<text x="64" y="598" class="mono" fill="#5b6673" font-size="15">react · spring boot · postgresql · docker</text>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

@@ -0,0 +1,84 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 630" width="1200" height="630" role="img" aria-labelledby="title desc">
<title id="title">Self-hosted infrastructure</title>
<desc id="desc">Architecture of the self-hosted infrastructure: a push to Gitea on the home server builds an image at home, Watchtower on the Hostinger VPS pulls it over Tailscale, and Traefik routes the public sites.</desc>
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#1e2530"/>
<stop offset="100%" stop-color="#15181d"/>
</linearGradient>
<linearGradient id="accent" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#26c6da"/>
<stop offset="100%" stop-color="#ffa726"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#4a5563"/>
</marker>
<marker id="arrowCyan" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#26c6da"/>
</marker>
</defs>
<style>
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; }
.sans { font-family: Roboto, Arial, sans-serif; }
.lbl { fill: #8b97a6; font-size: 17px; letter-spacing: .04em; }
.chip { fill: #cdd6e0; font-size: 19px; }
.cap { fill: #6c7887; font-size: 15px; letter-spacing: .18em; }
.name { fill: #cdd6e0; font-size: 22px; font-weight: 600; }
.sub { fill: #8b97a6; font-size: 16px; }
.arr { fill: #8b97a6; font-size: 15px; }
</style>
<rect width="1200" height="630" fill="url(#bg)"/>
<rect x="0" y="0" width="1200" height="4" fill="url(#accent)"/>
<text x="64" y="72" class="mono" fill="#26c6da" font-size="26" font-weight="600">Self-hosted infrastructure</text>
<text x="64" y="102" class="sans lbl">build at home, serve from the VPS</text>
<rect x="130" y="140" width="460" height="390" rx="18" fill="#1a222c" stroke="#26c6da" stroke-width="2"/>
<text x="154" y="168" class="sans cap" text-anchor="start">HOME SERVER "TRIBBLE"</text>
<rect x="154" y="186" width="412" height="130" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="174" y="220" class="sans name">Gitea</text>
<text x="174" y="246" class="sans sub">git, Actions runner, container registry</text>
<rect x="154" y="346" width="128" height="58" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="218" y="382" class="sans chip" style="font-size:16px" text-anchor="middle">Traefik</text>
<rect x="296" y="346" width="128" height="58" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="360" y="382" class="sans chip" style="font-size:16px" text-anchor="middle">Portainer</text>
<rect x="438" y="346" width="128" height="58" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="502" y="382" class="sans chip" style="font-size:16px" text-anchor="middle">Jellyfin</text>
<rect x="154" y="418" width="128" height="58" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="218" y="454" class="sans chip" style="font-size:16px" text-anchor="middle">AdGuard Home</text>
<rect x="296" y="418" width="128" height="58" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="360" y="454" class="sans chip" style="font-size:16px" text-anchor="middle">Paperless-ngx</text>
<rect x="438" y="418" width="128" height="58" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="502" y="454" class="sans chip" style="font-size:16px" text-anchor="middle">Tailscale</text>
<rect x="700" y="140" width="452" height="390" rx="18" fill="#1a222c" stroke="#ffa726" stroke-width="2"/>
<text x="724" y="168" class="sans cap" text-anchor="start">HOSTINGER VPS</text>
<rect x="724" y="206" width="404" height="90" rx="10" fill="#243040" stroke="#33475c"/>
<text x="744" y="240" class="sans name">Watchtower</text>
<text x="744" y="266" class="sans sub">pulls new images automatically</text>
<path d="M 736 296 V 484" stroke="#4a5563" stroke-width="2"/>
<text x="750" y="322" class="sans arr" text-anchor="start">deploy</text>
<rect x="752" y="330" width="216" height="52" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="770" y="362" class="sans chip" style="font-size:17px" text-anchor="start">Playground (this site)</text>
<path d="M 736 356 H 750" stroke="#4a5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
<path d="M 1000 356 H 976" stroke="#4a5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
<rect x="752" y="394" width="216" height="52" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="770" y="426" class="sans chip" style="font-size:17px" text-anchor="start">Pepper Pepperoni</text>
<path d="M 736 420 H 750" stroke="#4a5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
<path d="M 1000 420 H 976" stroke="#4a5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
<rect x="752" y="458" width="216" height="52" rx="10" fill="#212a35" stroke="#2f3a47"/>
<text x="770" y="490" class="sans chip" style="font-size:17px" text-anchor="start">To Be Played</text>
<path d="M 736 484 H 750" stroke="#4a5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
<path d="M 1000 484 H 976" stroke="#4a5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
<rect x="1000" y="330" width="128" height="180" rx="10" fill="#2a2118" stroke="#5c4326"/>
<text x="1016" y="368" class="sans name" text-anchor="start">Traefik</text>
<text x="1016" y="394" class="sans sub" text-anchor="start">TLS, routing</text>
<path d="M 40 251 H 150" stroke="#26c6da" stroke-width="2" fill="none" marker-end="url(#arrowCyan)"/>
<text x="44" y="240" class="mono arr" text-anchor="start">git push</text>
<path d="M 574 251 H 716" stroke="#26c6da" stroke-width="2" fill="none" marker-end="url(#arrowCyan)"/>
<text x="645" y="214" class="sans arr" text-anchor="middle">new image</text>
<text x="645" y="234" class="sans arr" text-anchor="middle">via Tailscale</text>
<line x1="64" y1="566" x2="1136" y2="566" stroke="#2a333e"/>
<text x="64" y="598" class="mono" fill="#5b6673" font-size="15">gitea · docker · traefik · tailscale · watchtower</text>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB