Skip to main content
Dejan Demonjić brand logoDejan Demonjić
Decision log
Work
About
Contact

Principal software engineer · Belgrade

Secure, multi-tenant .NET platforms, and the decisions behind them.

Identity servers, tenant isolation, gateways to physical door controllers, and the quality systems that keep a codebase honest. This log records what was decided, what was rejected, and what it cost.

  • Read the log
  • See the work

Now Building the identity platform for Hexavera: OpenIddict, mutual TLS for service clients, tenant isolation.

Latest entry

All entries

Field noteEngineering systems

Technical SEO for a Blazor site: what the crawler actually sees

A crawler sees bytes, not intent. Static server-side rendering, one content source for pages, sitemap and feeds, a real 404 and immutable fingerprinted assets get a Blazor site most of the way. The rest is reading your own output: an early export of this site showed a truncated title, modified dates hours before the published dates, an author link to nowhere and a configuration flag the renderer ignored. Each one with the rule it breaks and the fix.

16 Oct 2026 · 9 min read

From the log

All entries
  1. Decision recordEngineering systems

    The quality gate that could not see async code

    A gate is a measurement, and a measurement has blind spots you must find before you trust it. Our CRAP gate took complexity from source and coverage from a Cobertura report, and the two never met for an async method, because the compiler had moved its body into a state machine. Of 1,946 async methods, two showed any coverage. What that meant for the gate, why the measurement was left unfixed, and the two rules adopted instead.

    16 Oct 2026 · 8 min read

  2. Decision recordDevices at the edge

    Panel passwords are sealed to the host that uses them

    A secret that one process uses should be readable by that process alone. The decision record for the administrator passwords of access-control panels: write-only entry, a fresh AES-GCM key per secret wrapped with RSA-OAEP under the connector host's key, opened in memory only, one escrow export and then a key nobody can export, a TPM tier that excludes escrow, and why machine-scope DPAPI and the web runtime's key ring were the wrong tools.

    16 Oct 2026 · 8 min read

  3. Field noteDevices at the edge

    Talking to door controllers: what ISAPI teaches about typed outcomes

    A boolean cannot carry what an access-control panel answers. Three measured facts (a failed write with HTTP 200 and no status, an acknowledged write that changed nothing, a reused digest nonce the panel refused) turned a 27-member interface whose every write returned a boolean into a closed set of typed outcomes, a classification order, a read-back rule and a fresh challenge per request; asking which way a door fails added a deadline on anything that unlocks one.

    16 Oct 2026 · 9 min read

  4. Decision recordRealtime transports

    SignalR between a cloud and its sites

    A hub that pushes changes from a cloud to on-premises sites is a security boundary and a lifecycle problem: who may connect, what each connection hears, how long an admission holds, and how a client comes back after the server closes it. The design note: a service-client policy, a group per tenant, a fifteen-second sweep with the same check requests get, and a client that starts itself again because automatic reconnect does not follow a server-side Abort.

    16 Oct 2026 · 8 min read

  5. Decision recordRealtime transports

    Server-Sent Events in ASP.NET Core 10, and when to pick them over SignalR

    When a server talks and a client listens for the length of one request, Server-Sent Events is the right transport: plain HTTP, one direction, a text protocol a proxy carries and a browser reconnects by itself. .NET 10 made it a first-class result. The parts that bite are on the client: the protocol has rules, and some servers decide per response whether to answer with JSON or with a stream.

    16 Oct 2026 · 7 min read

  6. Decision recordMulti-tenant platforms

    One repository, several solutions

    Splitting a product line into repositories is a permissions decision wearing an architecture costume. Azure Repos permissions stop at the repository, so if nobody has to be kept from reading part of the code, one repository with several solution files keeps the compile-time safety that packages trade for version drift. The decision record, the reference matrix, and the test that holds it.

    16 Oct 2026 · 9 min read

Series

  1. Identity and access 5 parts · start with “One identity server for the cloud and for every site”
  2. Multi-tenant platforms 3 parts · start with “The tenant comes from the token, not from the header”
  3. Realtime transports 2 parts · start with “Server-Sent Events in ASP.NET Core 10, and when to pick them over SignalR”
  4. Devices at the edge 2 parts · start with “Talking to door controllers: what ISAPI teaches about typed outcomes”
  5. Engineering systems 3 parts · start with “Pre-MVP: make it right, never comply”

Selected work

All work
  1. Platform

    Hexavera

    A workforce and access-control platform: its identity server, its multi-tenant cloud, and the gateway between the cloud and physical door controllers.

    • .NET 10 · Blazor · OpenIddict · PostgreSQL · .NET Aspire
  2. Open source

    Osirion.Blazor

    An open source component library and Markdown CMS for Blazor, built to render completely under static server-side rendering. This site runs on it.

    • .NET 9 and 10 · Blazor static SSR · Markdig
    • NuGet
    • Source
  3. Website

    polovnjak.net

    A calculator for the cost of importing a used car into Serbia and Bosnia and Herzegovina: customs, VAT, homologation and first registration, in five languages.

    • Static pages · Cloudflare Pages and Functions · Turnstile
    • polovnjak.net
  4. Mobile game

    Sunbird

    A one-tap flying game on Google Play. Everyone flies the same course each day, and every flight can be replayed exactly.

    • JavaScript · Canvas 2D · Capacitor · .NET · Azure Cosmos DB
    • Google Play
Dejan Demonjić

Designing and building secure, multi-tenant .NET platforms, and writing down the decisions behind them.

Read

  • Decision log
  • Work
  • RSS feed

Contact

  • dejan@demonjic.com
  • Write to me
  • About

Elsewhere

© Dejan Demonjić. Written in Belgrade.