Aphrod-IT

Contact

● Available for consulting

Maria Ruth Nielsen

Fullstack .NET developer. I build the whole thing — data model, backend, UI, deployment — and stay with it after it ships

role
Fullstack Developer
based
Esbjerg, Denmark
stack
C# · .NET · Blazor · TypeScript · Vue 3 · SQL
open to
consulting, freelance builds
Get in touch
Maria Ruth Nielsen 2026

Stack

Languages
  • C#
  • TypeScript
  • SQL
Frameworks & APIs
  • .NET / ASP.NET Core
  • Blazor
  • Vue 3
  • EF Core
  • OData
Platforms
  • Umbraco
  • Optimizely
  • inriver PIM
Tooling and ops
  • Git
  • Docker
  • GitHub Actions
  • PostgreSQL
  • RabbitMQ
  • Caddy
  • Stripe

Case study

2026 · solo build

Silhouettes From Denmark

Webshop, headless CMS and back office for a jewellery business — designed, built, deployed and run by me

Visit silhouettesfromdenmark.dk ↗
Architecture

.NET 10 solution split into Web, Core, Data and CMS projects. The storefront is Blazor static SSR, with interactivity only where it earns its keep: the product gallery and the admin pages. Product content comes from a headless Umbraco through its Delivery API, cached with HybridCache, with doctypes kept in source control via uSync. Orders, stock and prices live in PostgreSQL through EF Core, and the cart is an encrypted cookie, so the shop holds no session state

The shop on desktop
A product page of the Silhouettes From Denmark webshop on a phone
Phone
Custom back office

Interactive Server pages behind OpenID Connect, for everything a CMS does poorly: orders to pack, where marking one as sent captures the payment and sends the shipping email; stock and prices edited inline in a QuickGrid; and a sales overview with monthly earnings, best sellers and a monthly VAT report as a PDF — in Danish, for the accountant, and without customer details

The back office page for product stock and prices
Stock & prices
The back office sales overview with monthly earnings, best sellers and a monthly PDF report
Sales

All orders, sales figures and customer details shown are test data.

Payments and email

Stripe Checkout with manual capture: the amount is reserved at checkout and only captured when the order is marked as sent, as Danish rules require. The customer's return and Stripe's webhook both confirm the order through one path, whichever arrives first. Transactional email goes through a database-backed outbox with retries (MailKit), and the shipping email carries a PDF receipt; monthly VAT reports are generated the same way with PDFsharp/MigraDoc

Security and privacy

Admin behind OpenID Connect with an email allowlist, rate limiting, security headers, and a Content Security Policy rolled out report-only first, so gaps are reported instead of breaking pages. Image resize URLs are HMAC-signed so the CMS cannot be used as a free image processor. A daily job strips customer details from orders past the two-year retention period stated in the privacy policy

Running it cheaply

Docker images built in GitHub Actions and pulled from GHCR onto a single 4 GB VPS that runs Caddy, the shop, Umbraco and PostgreSQL. Each container has a memory ceiling so one runaway service cannot starve the others, and image resizing is throttled so it fits next to Umbraco. Either app can be redeployed without taking the other down

Why it was built this way

Low running cost

Everything is open source and runs on one small VPS. No platform subscription and no per-order fee beyond Stripe's own, which matters for a small business with a modest order volume

Room to grow

The storefront keeps no state of its own and serves cached content as plain server-rendered HTML, so handling more traffic means a bigger server or another shop container — not a rewrite

Payments chosen from the requirements

MobilePay and Apple Pay were must-haves — they are how Danish customers expect to pay — and the owner plans to sell abroad eventually. Stripe covered both: MobilePay, Apple Pay and cards in one integration today, and the currencies and payment methods of new markets when the time comes

The right tool for each job

Umbraco gives the owner a familiar, user-friendly editor for products, pictures and pages. What a CMS does poorly — orders to pack, stock, prices, VAT reports — lives in a custom back office shaped around how the business actually works

Experience

  1. 03.2026 – now

    System Developer

    NDI Group A/S · Brørup

    Maintaining and extending a webshop and the integrations that aggregate and synchronise its data. Lead developer on a new implementation of the webshop's search and navigation

  2. 01.2025 – 02.2026

    Fullstack Developer

    Danish Safety Technology Authority · Esbjerg

    Maintenance, development and delivery of new features across a portfolio of systems supporting product safety in Denmark

  3. 03.2024 – 01.2025

    Fullstack Developer (student)

    Danish Safety Technology Authority · Esbjerg

    Development and maintenance of solutions for internal and external use, alongside my studies

  4. 2014 – 2021

    Midwife

    Haugesund Hospital · Norway

    Critical problem solving under pressure, task delegation and training of new staff

Education

2022 – 2025

AP Degree in Computer Science

Syddansk Erhversakademi, Esbjerg. Graduated with a 12 average — the top of the Danish grading scale

2011 – 2014

Bachelor of Midwifery

UC SYD, Esbjerg

Why a midwife writes good software

Seven years of high-stakes problem solving

Before code, I spent seven years as a midwife in Norway: making calls under pressure, delegating in a team, training new staff, and explaining complicated things to people who were scared. I changed direction at 34 without ever having written a line of code

That background is why I care about the parts of a system nobody demos — the retry logic, the audit trail, the error message and handling

Outside work I run IT Women Esbjerg with a small group of volunteers, organising technical and social events for women in tech

Get in touch

Consulting, a second pair of hands, or a whole build

Tell me a little about the project or the role. I read every message myself and reply personally

Contact me