§ 03 — Backend

Five projects, one dependency arrow.

The .NET backend is split into five projects with a strictly enforced dependency hierarchy. Build that breaks the rule fails immediately, which is the whole point: dependencies always flow toward the API project, never away from it.

The dependency graph

Reading the graph: Infrastructure has zero project references and may be referenced by anyone. Data sits on top of Infrastructure. Agent and Auth both sit on top of Data + Infrastructure, but they don't see each other. Api sits on top of all four and is the only project that knows about HTTP.

Why this shape

Infrastructure has no DB
So that LangfuseClient, ITokenEncryptor, and Redis primitives can be reused by the MCP service without dragging EF Core along.
Auth doesn't see Agent
JWT issuance, OAuth callbacks, token encryption have nothing to do with the agent loop. Keeping them separate means changes in one cannot ripple into the other.
Agent doesn't see Auth
The agent loop reads userId + tenantId as plain inputs. It never decides who the user is.
Api is the only HTTP layer
Endpoints, WebSocket handlers, DI wiring, and middleware live here. Lower layers are framework-agnostic.
Tests live in one project
tests/AgenticIT.Tests/ with Unit/, Integration/, Parity/. Integration tests use SQLite in-memory via AgenticITWebAppFactory.

What lives where

AgenticIT.Infrastructure

AgenticIT.Data

AgenticIT.Agent

AgenticIT.Auth

AgenticIT.Api

Cross-cutting rules

JSON

Global ConfigureHttpJsonOptions with JsonNamingPolicy.SnakeCaseLower. C# SourceMessageId ↔ JSON source_message_id. Dictionary<string, object?> keys are explicit strings and unaffected by the policy.

DbContext

Not thread-safe. Fire-and-forget Task.Run blocks must call IServiceScopeFactory.CreateAsyncScope() rather than capturing the request scope.

Build

0 warnings, 0 errors. All 473 tests must pass. Default test run excludes integration tests via default.runsettings; run with --filter "FullyQualifiedName~AgenticIT.Tests.Integration" to opt in.

Where to dive