How it's built internally

A tour of the internals for anyone evaluating Nafas beyond the quick start.

For anyone evaluating this beyond the quick start:

  • Ingestion is entirely in-process: an ILoggerProvider, an ActivityListener, and a MeterListener, each writing into a bounded per-signal Channel<T> (capacity 20,000, drop-on-full). A single hosted service drains all three, batches writes (up to 500 records or every second, whichever comes first), and persists them.
  • Storage is a thin interface (INafasIngestionWriter/ INafasQueryStore) with two concrete implementations, SQLite and SQL Server — no ORM, parameterized SQL, schema created and migrated at startup.
  • Alert evaluation (NafasAlertEvaluationHostedService) is a polling BackgroundService reusing the same query layer the dashboard's KPI views use, tracking one open-incident-per-rule at a time.
  • Real-time delivery to the browser is an in-process pub/sub (NafasLiveFeed) fed by the ingestion writer and alert evaluator, read by the dashboard's SSE endpoints — nothing here is a polling query.
  • The dashboard UI is a Vue 3 + Vite SPA (PrimeVue, Pinia, Chart.js, vue-i18n for English/Persian), built ahead of time and embedded directly into the assembly as embedded resources — a consumer installing the package gets the whole UI with no separate static-file deployment step, and no Node.js runtime on the host machine.
  • The whole API surface is a small hand-rolled router rather than ASP.NET Core's IEndpointRouteBuilder, because endpoint routing has been FrameworkReference-only since ASP.NET Core 3.0 and is unavailable to a netstandard2.x class library.