# C4 Level 2 — Container: WorkWingman # Render: d2 c4-container.d2 ../svg/c4-container.svg # https://c4model.com/#ContainerDiagram title: |md # WorkWingman — Containers (C4 L2) | {near: top-center} direction: down user: {label: "Job seeker\n[Person]"; shape: person} shell: { label: "Electron shell\n[electron/main.js]\n\nSpawns the API, hosts the UI,\nwill host the automation browser" style.fill: "#33608f" style.font-color: "#ffffff" renderer: { label: "Angular renderer\n[Angular 22 · 10 screens]\nsignals, hash routing" style.fill: "#4a7fb0" style.font-color: "#ffffff" } } api: { label: "Local API\n[ASP.NET Core .NET 10]\nloopback 127.0.0.1:5211 only" style.fill: "#2b6e58" style.font-color: "#ffffff" } store: {label: "LocalJsonStore\n[~/Wingman/data/*.json]\nsource of truth"; shape: cylinder} vault: {label: "KeePass vault\n[vault.kdbx]\nsecrets never cross HTTP"; shape: cylinder} browser: {label: "Playwright Chromium\n[persistent profile]\nscraper + automation"; shape: hexagon} external: { label: "External systems\n[LinkedIn · Workday · Google · Apple · Claude]" shape: cylinder style.fill: "#8a857c" style.font-color: "#ffffff" } user -> shell: "Clicks / approves" shell.renderer -> api: "JSON over HTTP\n(loopback)" api -> store: "Reads / writes" api -> vault: "Resolves secrets\nin-process" api -> browser: "Drives" browser -> external: "Scrapes jobs,\nfills forms" api -> external: "REST (Flurl + Polly)"