01Public demo available

Policy Operations API

A policy changes state, belongs to an organization and must never lose a concurrent edit. The API guarantees it with the token, the row version and an audit written alongside the change.

Context

A policy's lifecycle looks simple: draft, active, cancelled. The hard part is around it: that one organization never sees or touches another's policies, that every transition leaves a trace of who made it and why, and that two operators editing at once never overwrite each other unknowingly.

The project solves those three things in a .NET API on SQL Server, built as a public demonstration with synthetic data. A draft can be activated or cancelled; an active policy can be cancelled; cancelled is a final state. Every accepted transition records the actor, the time, the correlation id and the reason.

Architecture

Policy operations API architectureThe web interface calls the API, which validates the token, the organization and the policy version. The application layer runs the domain transitions. The infrastructure persists the policy and its audit entry in a single transaction in SQL Server.Web interfaceVue 3 · GitHub Pages.NET APIJWT · ETag and If-Match · ProblemDetailsApplicationuse cases · transitionsDomainDraft → Active → CancelledInfrastructureEF Core · rowversionSQL Serverpolicy and audit, one transactionorganization from the token · version required

The Vue interface, served as a static site, calls the API. The API requires a JWT token, takes the organization from one of its claims and exposes each policy's row version as an ETag; any change must carry that version in the If-Match header. The application layer runs the transition on the domain and the infrastructure saves the policy and its audit entry in a single transaction.

Decisions

  1. Modular monolith in four projects. Domain, application, infrastructure and API, on the long-term support version of .NET. The single-project layout could not demonstrate the boundaries the documentation promised; now architecture tests verify them.
  2. The organization comes from the token, not from the request. Every repository method requires the organization id and policy numbers are unique within it. A policy of another organization answers as missing, not as forbidden, so its existence is never revealed.
  3. Optimistic concurrency with a row version. Without an If-Match header the API asks for the precondition; with a stale version it answers with a concurrency conflict. Errors follow the Problem Details format with a stable code and a trace id, and the audit is written in the same transaction as the change.
  4. Public demo on a free tier, with its limits in plain sight. A single anonymous, rate-limited endpoint runs the whole scenario without sharing credentials. When the database wakes up after a pause, the API answers that the service is unavailable and says when to retry, instead of an opaque error. Continuous integration tests against a real SQL Server in a container.

What you can verify in the demo

  • Run the five-step scenario with one click: create a draft, activate it, watch an edit with a stale version get rejected, cancel and read the audit with its two transitions.
  • Follow each step on the architecture blueprint, which lights up the answering layer and marks the concurrency rejection in red.
  • Tell whether the run was real against SQL Server or simulated in the browser: the interface labels each case.
  • Copy the reproducible command to repeat the scenario from the terminal.

Stack

  • C#
  • .NET 10
  • EF Core
  • SQL Server
  • Azure