02 Work · May 2026 – Now

Portfolia

portfolia-cover-image

I wanted one place to show my work and write about it, and I wanted to own every layer of it. Portfolia is that platform: the public site you're reading, a blog, and a CMS where I edit and publish everything.

Backend:

  • .NET 10 API in Clean Architecture (Domain, Application, Infrastructure, API), with Domain-Driven Design aggregates and domain events

  • Wolverine for commands, queries and messaging, with a durable PostgreSQL outbox and scheduled messages for timed blog posts

  • Entity Framework Core 10 on PostgreSQL, including full-text search for the blog

  • Hybrid caching with FusionCache (in-memory plus Redis), and RabbitMQ for integration events

  • JWT access and refresh tokens, client-credential API clients, and permission-based authorisation where a request's rights are the overlap of the user's and the client's

  • Image uploads re-encoded to WebP with metadata stripped, stored in Azure Blob Storage behind signed links; secrets in Azure Key Vault

  • Rate limiting, an audit log and OpenTelemetry tracing

Frontend:

  • A pnpm and Turborepo monorepo with two TanStack Start apps (the public site and the CMS) sharing a design system

  • Server-side rendering, with the server acting as a backend-for-frontend, so tokens stay in httpOnly cookies and never reach the browser

  • React 19 with the React Compiler, Tailwind CSS v4 and shadcn/Radix components

  • A TipTap rich-text editor with autosave, revision history, image paste and embeds; code is highlighted on the server with shiki

Publishing and SEO:

Portfolio content is published as immutable releases that can be previewed and restored. Blog posts can be scheduled, previewed through signed links, unpublished or archived. Search engines get structured data (JSON-LD), a sitemap, RSS and Atom feeds, and an llms.txt for AI search.

Delivery:

Every push runs tests in GitHub Actions, builds Docker images to GitHub's container registry, and deploys blue/green on a Linux VPS behind Caddy: the new version starts beside the old one and takes traffic only once it's healthy.

  • portfolia-role-edit
  • portfolia-api-clients
  • portfolia-audit-logs
  • portfolia-media-explorer