1f695d3932
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
126 lines
9.7 KiB
XML
126 lines
9.7 KiB
XML
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 1720" font-family="Segoe UI, Arial, sans-serif">
|
||
<rect width="1440" height="1720" fill="#0B0E14"/>
|
||
|
||
<!-- header (compressed 56px scrolled state) -->
|
||
<rect width="1440" height="56" fill="#0B0E14" fill-opacity="0.9"/>
|
||
<line x1="0" y1="56" x2="1440" y2="56" stroke="#E8ECF2" stroke-opacity="0.08"/>
|
||
<rect x="120" y="14" width="28" height="28" rx="7" fill="#11151D" stroke="#E8ECF2" stroke-opacity="0.16"/>
|
||
<text x="134" y="33" fill="#E8ECF2" font-family="Consolas, monospace" font-size="12" font-weight="bold" text-anchor="middle">CB</text>
|
||
<text x="430" y="34" fill="#E8ECF2" font-size="13">Projects</text>
|
||
<line x1="430" y1="40" x2="478" y2="40" stroke="#3ECFAE" stroke-width="2"/>
|
||
<text x="510" y="34" fill="#9AA4B2" font-size="13">Experience</text>
|
||
<text x="610" y="34" fill="#9AA4B2" font-size="13">About</text>
|
||
<text x="680" y="34" fill="#9AA4B2" font-size="13">Contact</text>
|
||
<rect x="1176" y="13" width="144" height="30" rx="8" fill="#3ECFAE"/>
|
||
<text x="1238" y="33" fill="#062A22" font-size="12" font-weight="600" text-anchor="middle">Download CV ▾</text>
|
||
|
||
<!-- case study header -->
|
||
<text x="120" y="140" fill="#3ECFAE" font-family="Consolas, monospace" font-size="12" letter-spacing="2">CASE STUDY · PERSONAL PRODUCT</text>
|
||
<text x="120" y="204" fill="#E8ECF2" font-size="49" font-weight="600" letter-spacing="-0.7">JobTrack</text>
|
||
<rect x="340" y="172" width="92" height="28" rx="14" fill="#11151D" stroke="#3ECFAE" stroke-opacity="0.4"/>
|
||
<circle cx="358" cy="186" r="3.5" fill="#3ECFAE"/>
|
||
<text x="370" y="191" fill="#3ECFAE" font-family="Consolas, monospace" font-size="11">ACTIVE</text>
|
||
<text x="120" y="248" fill="#9AA4B2" font-size="18">A job-application workspace covering the full journey from application to follow-up.</text>
|
||
|
||
<g font-family="Consolas, monospace" font-size="12" fill="#E8ECF2">
|
||
<rect x="120" y="276" width="72" height="28" rx="14" fill="#171C26"/><text x="156" y="294" text-anchor="middle">.NET 9</text>
|
||
<rect x="200" y="276" width="66" height="28" rx="14" fill="#171C26"/><text x="233" y="294" text-anchor="middle">React</text>
|
||
<rect x="274" y="276" width="110" height="28" rx="14" fill="#171C26"/><text x="329" y="294" text-anchor="middle">TypeScript</text>
|
||
<rect x="392" y="276" width="76" height="28" rx="14" fill="#171C26"/><text x="430" y="294" text-anchor="middle">SQLite</text>
|
||
<rect x="476" y="276" width="86" height="28" rx="14" fill="#171C26"/><text x="519" y="294" text-anchor="middle">FastAPI</text>
|
||
<rect x="570" y="276" width="76" height="28" rx="14" fill="#171C26"/><text x="608" y="294" text-anchor="middle">Ollama</text>
|
||
<rect x="654" y="276" width="76" height="28" rx="14" fill="#171C26"/><text x="692" y="294" text-anchor="middle">Docker</text>
|
||
</g>
|
||
<text x="1200" y="294" fill="#3ECFAE" font-size="14">Repository ↗</text>
|
||
|
||
<!-- hero screenshot: browser frame -->
|
||
<rect x="120" y="336" width="1200" height="520" rx="16" fill="#171C26" stroke="#E8ECF2" stroke-opacity="0.16"/>
|
||
<rect x="120" y="336" width="1200" height="40" rx="16" fill="#11151D"/>
|
||
<rect x="120" y="360" width="1200" height="16" fill="#11151D"/>
|
||
<circle cx="148" cy="356" r="5" fill="#5C6675"/><circle cx="166" cy="356" r="5" fill="#5C6675"/><circle cx="184" cy="356" r="5" fill="#5C6675"/>
|
||
<rect x="560" y="346" width="320" height="20" rx="10" fill="#171C26"/>
|
||
<text x="720" y="360" fill="#5C6675" font-family="Consolas, monospace" font-size="11" text-anchor="middle">jobtrack.local</text>
|
||
<!-- mock app content -->
|
||
<rect x="150" y="400" width="220" height="426" rx="8" fill="#11151D"/>
|
||
<rect x="390" y="400" width="900" height="60" rx="8" fill="#11151D"/>
|
||
<text x="410" y="436" fill="#9AA4B2" font-size="14">Applications · filters · search</text>
|
||
<g fill="#11151D">
|
||
<rect x="390" y="474" width="900" height="52" rx="6"/>
|
||
<rect x="390" y="534" width="900" height="52" rx="6"/>
|
||
<rect x="390" y="594" width="900" height="52" rx="6"/>
|
||
<rect x="390" y="654" width="900" height="52" rx="6"/>
|
||
<rect x="390" y="714" width="900" height="52" rx="6"/>
|
||
</g>
|
||
<g font-family="Consolas, monospace" font-size="11">
|
||
<rect x="1160" y="488" width="92" height="24" rx="12" fill="#0F2B24"/><text x="1206" y="504" fill="#3ECFAE" text-anchor="middle">INTERVIEW</text>
|
||
<rect x="1160" y="548" width="92" height="24" rx="12" fill="#2E2410"/><text x="1206" y="564" fill="#E5A93D" text-anchor="middle">WAITING</text>
|
||
<rect x="1160" y="608" width="92" height="24" rx="12" fill="#171C26"/><text x="1206" y="624" fill="#9AA4B2" text-anchor="middle">APPLIED</text>
|
||
</g>
|
||
<text x="720" y="800" fill="#5C6675" font-size="13" text-anchor="middle">[ 2× capture: applications table with status filters — seeded demo data ]</text>
|
||
|
||
<!-- TL;DR box -->
|
||
<rect x="120" y="896" width="800" height="180" rx="12" fill="#171C26"/>
|
||
<rect x="120" y="896" width="3" height="180" fill="#3ECFAE"/>
|
||
<text x="148" y="932" fill="#5C6675" font-family="Consolas, monospace" font-size="11" letter-spacing="1.5">TL;DR</text>
|
||
<text x="148" y="964" fill="#E8ECF2" font-size="15"><tspan font-weight="600">What</tspan> Full-stack job-application tracker: pipeline, correspondence, attachments, analytics</text>
|
||
<text x="148" y="992" fill="#E8ECF2" font-size="15"><tspan font-weight="600">Why</tspan> Real problem — my own job search needed production-grade tooling</text>
|
||
<text x="148" y="1020" fill="#E8ECF2" font-size="15"><tspan font-weight="600">Stack</tspan> React + ASP.NET Core + SQLite · FastAPI/Ollama AI service · Docker Compose</text>
|
||
<text x="148" y="1048" fill="#E8ECF2" font-size="15"><tspan font-weight="600">Role</tspan> Everything: product, backend, frontend, ops, security</text>
|
||
|
||
<!-- mini TOC -->
|
||
<g font-size="13">
|
||
<text x="1080" y="932" fill="#5C6675" font-family="Consolas, monospace" font-size="11" letter-spacing="1.5">ON THIS PAGE</text>
|
||
<text x="1080" y="964" fill="#9AA4B2">Problem</text>
|
||
<rect x="1064" y="982" width="2" height="16" fill="#3ECFAE"/>
|
||
<text x="1080" y="994" fill="#E8ECF2">Architecture</text>
|
||
<text x="1080" y="1024" fill="#9AA4B2">Decisions</text>
|
||
<text x="1080" y="1054" fill="#9AA4B2">Security</text>
|
||
<text x="1080" y="1084" fill="#9AA4B2">Screenshots</text>
|
||
<text x="1080" y="1114" fill="#9AA4B2">What's next</text>
|
||
</g>
|
||
|
||
<!-- Architecture section -->
|
||
<text x="120" y="1160" fill="#3ECFAE" font-family="Consolas, monospace" font-size="12" letter-spacing="2">ARCHITECTURE</text>
|
||
<text x="120" y="1204" fill="#E8ECF2" font-size="31" font-weight="600">Four services, one compose file</text>
|
||
|
||
<!-- diagram -->
|
||
<rect x="120" y="1240" width="1200" height="300" rx="12" fill="#11151D" stroke="#E8ECF2" stroke-opacity="0.08"/>
|
||
<!-- nodes -->
|
||
<g>
|
||
<rect x="170" y="1330" width="180" height="72" rx="8" fill="#171C26" stroke="#E8ECF2" stroke-opacity="0.16"/>
|
||
<text x="260" y="1360" fill="#E8ECF2" font-size="14" text-anchor="middle">React SPA</text>
|
||
<text x="260" y="1382" fill="#5C6675" font-family="Consolas, monospace" font-size="11" text-anchor="middle">nginx · PWA</text>
|
||
|
||
<rect x="440" y="1330" width="200" height="72" rx="8" fill="#171C26" stroke="#3ECFAE" stroke-opacity="0.5"/>
|
||
<text x="540" y="1360" fill="#E8ECF2" font-size="14" text-anchor="middle">ASP.NET Core API</text>
|
||
<text x="540" y="1382" fill="#5C6675" font-family="Consolas, monospace" font-size="11" text-anchor="middle">.NET 9 · auth · rules</text>
|
||
|
||
<rect x="730" y="1276" width="180" height="64" rx="8" fill="#171C26" stroke="#E8ECF2" stroke-opacity="0.16"/>
|
||
<text x="820" y="1302" fill="#E8ECF2" font-size="14" text-anchor="middle">SQLite + files</text>
|
||
<text x="820" y="1322" fill="#5C6675" font-family="Consolas, monospace" font-size="11" text-anchor="middle">EF Core · attachments</text>
|
||
|
||
<rect x="730" y="1364" width="180" height="64" rx="8" fill="#171C26" stroke="#E8ECF2" stroke-opacity="0.16"/>
|
||
<text x="820" y="1390" fill="#E8ECF2" font-size="14" text-anchor="middle">AI service</text>
|
||
<text x="820" y="1410" fill="#5C6675" font-family="Consolas, monospace" font-size="11" text-anchor="middle">FastAPI → Ollama</text>
|
||
|
||
<rect x="1000" y="1330" width="180" height="72" rx="8" fill="#171C26" stroke="#E5A93D" stroke-opacity="0.5"/>
|
||
<text x="1090" y="1360" fill="#E8ECF2" font-size="14" text-anchor="middle">Gmail API</text>
|
||
<text x="1090" y="1382" fill="#8A6114" font-family="Consolas, monospace" font-size="11" text-anchor="middle">external · OAuth2</text>
|
||
</g>
|
||
<!-- edges -->
|
||
<g stroke="#3ECFAE" stroke-width="1.5" fill="none">
|
||
<path d="M350 1366 H440"/>
|
||
<path d="M640 1352 L730 1308"/>
|
||
<path d="M640 1380 L730 1396"/>
|
||
</g>
|
||
<path d="M640 1366 H960 M960 1366 H1000" stroke="#E5A93D" stroke-width="1.5" stroke-dasharray="4 4" fill="none"/>
|
||
<text x="380" y="1356" fill="#5C6675" font-family="Consolas, monospace" font-size="10">/api</text>
|
||
<text x="930" y="1356" fill="#8A6114" font-family="Consolas, monospace" font-size="10">import</text>
|
||
<text x="148" y="1276" fill="#5C6675" font-family="Consolas, monospace" font-size="11">hover: node highlights its edges, others dim to 60% (desktop only — fully legible static)</text>
|
||
|
||
<!-- decisions preview -->
|
||
<text x="120" y="1600" fill="#3ECFAE" font-family="Consolas, monospace" font-size="12" letter-spacing="2">KEY DECISIONS & TRADE-OFFS</text>
|
||
<text x="120" y="1644" fill="#E8ECF2" font-size="16"><tspan fill="#3ECFAE" font-family="Consolas, monospace">01</tspan> Local AI (Ollama) over a cloud API — privacy of job-search data + zero per-call cost, traded against setup complexity.</text>
|
||
<text x="120" y="1676" fill="#E8ECF2" font-size="16"><tspan fill="#3ECFAE" font-family="Consolas, monospace">02</tspan> No offline cache in the PWA — deliberate: frequent deploys made stale builds a worse failure than offline gaps.</text>
|
||
</svg>
|