Skip to main content

naumche@senior-dev:~$ whoami
→ Full Stack .NET Developer

About this page, specifically

This is a landing page built to double as a CV — a real ASP.NET Core application, deployed the way a real one would be, not a static template. It's also a from-scratch .NET port of the Laravel version of this same site, built to show the same engineering discipline carries across stacks. A few things worth pointing out:

Application

  • → The animated chart on the ISG Macedonia entry is a React component, dropped in alongside the ASP.NET Core backend to show some frontend work too.
  • → The visit counter below and the app's cache both run on Redis — and degrade gracefully instead of crashing the page if Redis is ever unreachable.
  • → Submitting the contact form dispatches a Hangfire background job (Redis-backed) that sends a real email over SMTP — protected by Cloudflare Turnstile so it isn't just a bot magnet — and posts to Slack over a plain Incoming Webhook, so a new message doesn't just sit in an inbox.
  • → Page views are tracked server-side, straight to GA4's Measurement Protocol — no analytics JavaScript ships to the browser at all.
  • → A failed contact-notification job triggers a separate Slack alert once Hangfire's automatic retries are exhausted, via an IApplyStateFilter reacting to the job's failed-state transition — not a try/catch inside the job itself, which would silently defeat the retries.
  • → The dark/light toggle in the nav is a real preference, persisted in the browser — light by default regardless of your system setting.
  • → An xUnit integration test suite — real HTTP requests against real routes via WebApplicationFactory, covering all of the above — fully isolated (in-memory SQLite, mocked Redis/Hangfire/HTTP), so it needs no real Redis, mail server, or Turnstile account to run.

Infrastructure

↓ ↓ SSH deploy deploy status Hetzner VPS
Browser
Cloudflare Tunnel DNS · TLS · Turnstile · no inbound port
web Kestrel
(ASP.NET Core)
worker Hangfire server
(Redis-backed jobs)
MySQL
Redis
S3 (LocalStack)
GitHub Actions tests · analyzers · format · audits · gitleaks · docker smoke test
Slack leads · alerts · CI/CD status
— request path    —•• CI/CD & Slack notifications
  • → Fully Dockerized — Kestrel serves the app directly (a single process, no PHP-FPM-style manager needed), plus MySQL, Redis, and LocalStack as separate services, for local dev and production alike.
  • → The CV download streams the PDF straight from S3 (LocalStack-backed in dev) via the AWS SDK's IAmazonS3.
  • → Runs on the same Hetzner VPS as the Laravel version, isolated in its own Docker stack and reached via a Cloudflare Tunnel — no additional inbound port opened on the shared server.

Performance & accessibility

  • → Critical CSS is inlined (via Beasties) and everything else deferred, below-the-fold sections use content-visibility: auto so the browser skips laying them out until scrolled into view, and fonts are self-hosted with metric-matched fallbacks (via fontaine) so nothing shifts when they load.
  • → The site aims to pass WCAG checks with proper landmarks, a skip-to-content link, and verified color contrast.
  • → Structured data (JSON-LD), and Open Graph tags — so search engines and link previews see something more useful than a bare title.

Delivery

  • → Roslyn analyzers run at a strict, nullable-enabled level (pinned to a specific SDK analysis level for reproducibility) as the PHPStan-L9 equivalent, and dotnet format as the Pint-check equivalent, plus a custom check that fails the build over a stray Console.WriteLine or other leftover debug output.
  • → dotnet list package --vulnerable and npm audit scan every dependency for known vulnerabilities, and gitleaks scans the full git history for accidentally-committed secrets — on every push, not just once.
  • → Before deploying, CI builds the actual production Docker image and boots it standalone — no MySQL, Redis, or S3 attached — then confirms the home and about pages return 200, the hashed CSS asset referenced in the HTML actually resolves, and critical CSS is inlined. Source-level tests can't catch build/packaging bugs like a missing manifest file or an asset silently dropped by dotnet publish — this step exists because both of those really happened during development.
  • → GitHub Actions runs all of the above on every push to main, then deploys straight to the server over SSH (using a key scoped only to this app's own directory) only if every check is green — with a Slack notification either way. This page updates itself.

Visit #866, tracked in Redis. Yes, you can refresh.