Technology Stack Document
Technology Stack Document — Heimdall API
1. Purpose
This document is the single source of truth for the technologies used to build the Heimdall API — the runtime platform, language, first-party libraries, database, data-access stack, cross-cutting concerns, and testing tools, together with the version each is pinned to and the role it plays.
Every other document in this folder references this document for technical choices instead of restating them, so that:
- The domain documents (Vision , System Requirements , Use Case Specification ) stay focused on what the system does.
- The Operations & Infrastructure Document stays focused on the platform’s structure and operations.
- The Testing Specification Document stays focused on how to test.
- Technology versions and roles are maintained in exactly one place.
Rule: when a technology choice changes, it changes here first. Other documents link to this one rather than duplicating the detail.
2. Platform & Language
| Concern | Choice | Notes |
|---|---|---|
| Runtime / framework | .NET 10 (net10.0) | Every project targets net10.0. The Web API uses the Microsoft.NET.Sdk.Web SDK; libraries use Microsoft.NET.Sdk. |
| Language | C# 14 | C# 14 is the default language version for net10.0, so it is used implicitly — no explicit <LangVersion> is set, which keeps the language pinned to the target framework’s default. |
| Language features | Nullable enabled, ImplicitUsings enabled | Applied consistently across all production and test projects. |
Why explicit: C# 14 ships with and is the default for .NET 10. New code may freely use C# 14 features (collection expressions, primary constructors — already used e.g. in Startup, etc.). Do not pin an older <LangVersion>; let it track the .NET 10 default.
3. First-Party Libraries (ArturRios.*)
The project is built on a set of the author’s own reusable libraries, all published under the ArturRios package prefix. They are consumed as NuGet PackageReferences. The table lists every one currently in use, its pinned version, where it is referenced, and its role.
| Package | Version | Referenced by | Role |
|---|---|---|---|
| ArturRios.Util | 2.1.0 | Command, Domain, Shared, Data | Core cross-cutting utilities. Provides the standard DataOutput<T> result type (namespace ArturRios.Output) that handlers return, password hashing helpers (ArturRios.Util.Hashing), HTTP helpers (ArturRios.Util.Http), cryptographically strong random text (ArturRios.Util.Random.CustomRandom, used to mint the verification and password reset tokens), and general-purpose helpers used throughout the codebase. 1.5.0 is a floor, not a preference: earlier versions ignored CustomRandom.Text’s character-set flags for all but the first character of each set and drew from System.Random rather than RandomNumberGenerator, which made the security tokens neither URL-safe nor cryptographically sourced. |
| ArturRios.Util.WebApi | 5.1.0 | WebApi | Web API foundation. Supplies the WebApiStartup base class — a fixed standard sequence (configuration, controllers, Swagger, then forwarded headers, tracing, exception handling, CORS and authentication in the pipeline) that Startup completes in ConfigureServices — environment/configuration loading (ArturRios.Util.WebApi.Configuration), the security stack (role attributes/enums/extensions/middleware — e.g. [AllowAnonymous], role requirements), JWT issuance & validation (namespace ArturRios.Jwt), exception & authentication middleware, Swagger wiring, and the ToActionResult extensions that map a DataOutput<T> to an HTTP response. 5.x requires ArturRios.Util 2.1.0 and Google.Apis.Auth 1.76.0, which is why both are pinned there. |
| ArturRios.Jwt | 1.3.0 | WebApi | Token signing and signature validation (JwtHandler, JwtConfiguration, JwtKey). Arrives transitively through ArturRios.Util.WebApi, which asks for 1.2.0, and is declared on the WebApi project, which uses it directly. 1.3.0 is a floor: it accepts HS256 only, the one algorithm tokens are signed with. It checks the signature and lifetime but not the issuer or the audience, which the API checks itself (NFR-30). |
| ArturRios.Mediator | 2.0.0 | Command, Query, WebApi | Lightweight CQRS mediator. Provides CommandMediator / QueryMediator and the handler contracts (ICommandHandlerAsync, IQueryHandlerAsync, IPaginatedQueryHandlerAsync) that dispatch a command/query to its single handler. |
| ArturRios.Data.Relational.Core | 5.0.0 | Command, Query, Domain | Provider-agnostic relational data layer. Provides entity base types, the repository abstractions the handlers depend on (IAsyncRepository<T, long>, IAsyncReadOnlyRepository<T, long>), the EF Core DbContext base plus diagnostics options, and the DI entry point AddDataConfigFromEnvironment<TDbContext>(prefix) that binds the context to a connection from the environment. Entities derive from Entity<long>, and the repository contracts carry the key type. |
| ArturRios.Data.PostgreSql | 3.0.2 | Data | PostgreSQL binding for the relational core. Provides AddPostgreSqlProvider(), which wires EF Core to Npgsql so the relational layer runs against PostgreSQL. |
| ArturRios.Messaging | 1.3.0 | WebApi | Outbound email. Provides IEmailService and MailgunEmailService (namespace ArturRios.Messaging.Email), which sends plain-text transactional mail through the Mailgun HTTP API. Used by UC-06’s verification email and UC-12’s password reset email. Reads MAILGUN_API_KEY, MAILGUN_DOMAIN, and the optional MAILGUN_API_VERSION from the environment at call time. |
| ArturRios.Util.Test | 5.0.0 | all test projects | Testing toolkit (see §7). Provides the category test attributes ([UnitFact]/[UnitTheory], [FunctionalFact]/[FunctionalTheory]), the WebApiTest<TEntryPoint> functional base class, FakeRepository<T, long>, AsyncFakeRepository<T, long> (async repository fake with an async-capable Query()), FakeScheduler, and CustomAssert. |
ArturRios.Outputis a namespace surfaced by theArturRios.Utilfamily, not a separately referenced package.
4. Relational Database
| Concern | Choice |
|---|---|
| Relational database | PostgreSQL — the sole supported relational database for the project. |
| Provider integration | ArturRios.Data.PostgreSql → AddPostgreSqlProvider() (EF Core over Npgsql). |
| Connection configuration | Read from environment variables HEIMDALL_DATA_CONNECTIONSTRING and HEIMDALL_DATA_DATABASETYPE (PostgreSql) via AddDataConfigFromEnvironment<AppDbContext>("HEIMDALL_DATA"). |
PostgreSQL is used in every environment, including automated tests — functional tests run against a real PostgreSQL instance provisioned by Testcontainers (never an in-memory provider), so behavior matches production. There is no secondary/alternate relational engine.
5. Data Layer (Entity Framework Core)
| Concern | Choice | Version |
|---|---|---|
| ORM | Entity Framework Core (code-first) | 10.x |
| Design-time / migrations | Microsoft.EntityFrameworkCore.Design (enables dotnet ef; the Data library is its own startup project) | 10.0.12 |
| Naming convention | EFCore.NamingConventions — maps entities to snake_case, singular table/column names | 10.0.1 |
| Context | AppDbContext, based on the ArturRios.Data.Relational.Core context base, configured via entity maps (ArturRios.Heimdall.Data.EntityMaps) | — |
| Diagnostics | DbContextDiagnosticsOptions — sensitive-data logging & detailed errors are on only outside Production (they would expose password hashes, salts, e-mails) | — |
| Startup seeding | DatabaseSeeder seeds the roles and the master System Admin on startup | — |
The data access pattern is repository-based: application handlers depend on IAsyncReadOnlyRepository<T, long> / IAsyncRepository<T, long> (from ArturRios.Data.Relational.Core) rather than on DbContext directly, which is also what makes them unit-testable with FakeRepository<T, long>.
6. Cross-Cutting Technologies
| Concern | Technology | Version | How it is used |
|---|---|---|---|
| Input validation | FluentValidation | 12.1.1 | Command inputs have IValidator<TCommand> implementations (e.g. CreateScopeCommandValidator), registered in DI and invoked inside the handlers. |
| Logging | Serilog (Serilog, Serilog.AspNetCore) | 4.4.0 / 10.0.0 | Structured logging wired through Host.UseSerilog(), with JSON formatting; the log directory and the retention period are configurable via environment variables (NFR-22). |
| Authentication / authorization | JWT via ArturRios.Util.WebApi and ArturRios.Jwt | (see §3) | Signed bearer tokens; issuer, audience, secret, and expiration are supplied via HEIMDALL_AUTH_* environment variables. Role-based authorization and an AuthenticationMiddleware gate the endpoints. |
| Google ID token verification | Google.Apis.Auth | 1.77.0 | UC-25’s GoogleIdTokenVerifier calls GoogleJsonWebSignature.ValidateAsync to check an incoming ID token’s signature, issuer, audience, and expiration (FR-GO-11, NFR-13) before its claims are trusted. Arrives transitively through ArturRios.Util.WebApi and is declared explicitly on the WebApi project because that project uses its types directly. Why not the library’s own verifier: ArturRios.Util.WebApi ships IGoogleTokenVerifier, but its GoogleTokenPayload carries only sub, email, and email_verified — it cannot supply the name and picture claims a Google User is populated from (FR-GO-05), so UC-25 declares IGoogleIdTokenVerifier in the application layer and implements it here. |
| Local token validation | Microsoft.IdentityModel.JsonWebTokens | 8.23.0 | JsonWebTokenHandler, used by UC-25’s LocalGoogleIdTokenVerifier — the functional suite’s stand-in for Google, which validates locally signed ID tokens (see the Testing Specification §10). Also transitive, via ArturRios.Jwt; the explicit reference must match the version that package resolves, since a lower one fails restore with NU1605. |
| Result / error model | DataOutput<T> (namespace ArturRios.Output, from the ArturRios.Util family) | (see §3) | Handlers return success/errors/messages/data on a DataOutput<T> instead of throwing; ToActionResult maps it to an HTTP response. |
| API documentation | Swagger / OpenAPI (via ArturRios.Util.WebApi) | — | Generated and served by the standard sequence in the environments it allows, described by SwaggerConfiguration (options.Swagger.ConfigureGenerator), which also defines the bearer scheme. |
| Outbound email | Mailgun via ArturRios.Messaging | (see §3) | Verification (UC-06) and password reset (UC-12) emails. Startup.AddEmailSenders registers the Mailgun-backed senders only when MAILGUN_API_KEY and MAILGUN_DOMAIN are both set, and logging senders otherwise — so local runs and the functional suite work without credentials and never reach the network. Delivery failures are logged, never thrown: an anonymous caller’s response must not vary with whether the mail went out. |
| Metrics | OpenTelemetry (OpenTelemetry.Extensions.Hosting, .Instrumentation.AspNetCore, .Instrumentation.Http, .Exporter.Prometheus.AspNetCore) | 1.19.1 (instrumentation 1.19.0) / exporter 1.19.1-beta.1 | ASP.NET Core, HttpClient, System.Runtime, Kestrel, EF Core and Npgsql meters, served for Prometheus at /metrics on the private port HEIMDALL_METRICS_PORT (9464) only. The exporter has never had a stable release; it is accepted as a beta because it only formats what the stable SDK collected, on a port that is never published. |
| Configuration | .env.<environment> files + environment variables | — | Loaded by the ArturRios.Util.WebApi configuration loader; .env* files are copied next to the built assembly. |
7. Testing Technologies
These are the technologies mandated for tests. How they are applied to each use case (naming, structure, coverage, the per-use-case workflow) is defined in the Testing Specification Document ; this section is the canonical list of the tools and versions.
| Concern | Technology | Version | How it is used |
|---|---|---|---|
| Test framework | xUnit v3 (xunit.v3.mtp-off, xunit.runner.visualstudio) | 4.0.2 / 4.0.1 | The test framework for every test project. The mtp-off flavour runs through VSTest, so dotnet test, its --filter and the .trx logger work as before. |
| Test SDK / runner | Microsoft.NET.Test.Sdk | 18.10.1 | Test host/runner integration for dotnet test and IDEs. |
| Coverage | coverlet.collector | 10.1.0 | Collects code coverage during test runs. |
| Test helpers & doubles | ArturRios.Util.Test | 5.0.0 | Category attributes ([UnitFact]/[FunctionalFact], which stamp a Category trait), the WebApiTest<TEntryPoint> functional base class (spins up the host via WebApplicationFactory<T> and exposes an HttpGateway + authentication helpers), FakeRepository<T, long>, AsyncFakeRepository<T, long> (async repository fake whose Query() is async-capable, for unit-testing handlers that depend on IAsyncReadOnlyRepository<T, long>/IAsyncRepository<T, long>), FakeScheduler, and CustomAssert. |
| Mocking | Moq | 4.21.0 | The single mocking library for stubbing non-repository collaborators (validators, mediators, services). Do not introduce a second mocking framework. |
| Test data generation | Bogus | 35.6.5 | The standard way to generate entities/commands/DTOs (Faker<T>) instead of large inline literals or shared fixtures. |
| Functional database | Testcontainers (Testcontainers.PostgreSql) | 4.16.0 | Provisions a real, throwaway PostgreSQL container for functional (end-to-end) tests, so tests run against the same engine as production. |
Note: Moq and Bogus were pinned to the versions above when the first tests needing them were written (UC-03’s handler unit tests). Keep every test project on the same versions.
Tests are split by category — unit tests exercise Command/Query handlers and Domain behavior in isolation; functional tests exercise the Web API end-to-end against Testcontainers PostgreSQL. Run one kind at a time with dotnet test --filter "Category=Unit" or "Category=Functional".
8. Version Summary
| Category | Package / Tool | Version |
|---|---|---|
| Platform | .NET | 10 (net10.0) |
| Language | C# | 14 (framework default) |
| First-party | ArturRios.Util | 2.1.0 |
| First-party | ArturRios.Util.WebApi | 5.1.0 |
| First-party | ArturRios.Messaging | 1.3.0 |
| First-party | ArturRios.Util.Test | 5.0.0 |
| First-party | ArturRios.Mediator | 2.0.0 |
| First-party | ArturRios.Data.Relational.Core | 5.0.0 |
| First-party | ArturRios.Data.PostgreSql | 3.0.2 |
| Data | Microsoft.EntityFrameworkCore.Design | 10.0.12 |
| Data | EFCore.NamingConventions | 10.0.1 |
| Authentication | Google.Apis.Auth | 1.77.0 |
| Authentication | Microsoft.IdentityModel.JsonWebTokens | 8.23.0 |
| Validation | FluentValidation | 12.1.1 |
| Logging | Serilog | 4.4.0 |
| Logging | Serilog.AspNetCore | 10.0.0 |
| Metrics | OpenTelemetry.Extensions.Hosting | 1.19.1 |
| Metrics | OpenTelemetry.Instrumentation.AspNetCore | 1.19.0 |
| Metrics | OpenTelemetry.Instrumentation.Http | 1.19.0 |
| Metrics | OpenTelemetry.Exporter.Prometheus.AspNetCore | 1.19.1-beta.1 |
| Testing | xunit.v3.mtp-off | 4.0.2 |
| Testing | xunit.runner.visualstudio | 4.0.1 |
| Testing | Microsoft.NET.Test.Sdk | 18.10.1 |
| Testing | coverlet.collector | 10.1.0 |
| Testing | Testcontainers.PostgreSql | 4.16.0 |
| Testing | Moq | 4.21.0 |
| Testing | Bogus | 35.6.5 |