Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

Layer 5: MyApp.Api -- The Production Host

This is where the chain becomes a deployable application. The API project references MyApp.Domain (and transitively, everything else). It wires the DI container, exposes controllers, and optionally enables compliance validation.

DI Registration

// Program.cs
var builder = WebApplication.CreateBuilder(args);

// Wire the requirement chain
builder.Services.AddScoped<IUserRolesSpec, AuthorizationService>();
builder.Services.AddScoped<IJwtRefreshSpec, JwtRefreshService>();

// Optional: enable compliance mode for audit-sensitive operations
builder.Services.AddScoped<UserRolesValidator>(sp =>
    new UserRolesValidator(sp.GetRequiredService<IUserRolesSpec>()));

// Optional: enable requirement compliance checking at startup
builder.Services.AddHostedService<RequirementComplianceCheck>();

var app = builder.Build();
app.MapControllers();
app.Run();

Controller -- Normal Production Flow

namespace MyApp.Api.Controllers;

using MyApp.Specifications;
using MyApp.SharedKernel;
using MyApp.Requirements.Features;

[ApiController]
[Route("api/users")]
[ForRequirement(typeof(UserRolesFeature))]
public class UsersController : ControllerBase
{
    private readonly IUserRolesSpec _spec;

    public UsersController(IUserRolesSpec spec) => _spec = spec;

    [HttpPost("{targetId}/role")]
    [ForRequirement(typeof(UserRolesFeature), nameof(UserRolesFeature.AdminCanAssignRoles))]
    public IActionResult AssignRole(Guid targetId, [FromBody] AssignRoleRequest request)
    {
        var actingUser = HttpContext.GetCurrentUser();
        var targetUser = _users.GetById(new UserId(targetId));
        var role = _roles.GetById(new RoleId(request.RoleId));

        var result = _spec.AssignRole(actingUser, targetUser, role);

        return result.IsSuccess
            ? Ok(new { message = "Role assigned" })
            : BadRequest(new { error = result.Reason });
    }
}

The [ForRequirement] on the controller and action method means the generated OpenAPI schema includes requirement metadata:

{
  "paths": {
    "/api/users/{targetId}/role": {
      "post": {
        "x-requirement": "UserRolesFeature",
        "x-acceptance-criterion": "AdminCanAssignRoles",
        "summary": "Assign a role to a user"
      }
    }
  }
}

Startup Compliance Check

public class RequirementComplianceCheck : IHostedService
{
    private readonly ILogger<RequirementComplianceCheck> _logger;

    public Task StartAsync(CancellationToken ct)
    {
        // TraceabilityMatrix is source-generated
        foreach (var (type, entry) in TraceabilityMatrix.Entries)
        {
            var info = RequirementRegistry.All[type];
            var totalACs = info.AcceptanceCriteria.Length;
            var testedACs = entry.AcceptanceCriteriaCoverage.Count;

            if (testedACs < totalACs)
                _logger.LogWarning("{Feature}: {Tested}/{Total} ACs tested ({Missing} missing)",
                    info.Title, testedACs, totalACs,
                    string.Join(", ", info.AcceptanceCriteria
                        .Except(entry.AcceptanceCriteriaCoverage.Keys)));
            else
                _logger.LogInformation("{Feature}: all {Total} ACs covered",
                    info.Title, totalACs);
        }

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken ct) => Task.CompletedTask;
}

DLL Artifacts at Build Time

After dotnet build, the solution produces:

bin/
├── MyApp.Requirements.dll           ← Feature types, AC methods, generated attributes
├── MyApp.SharedKernel.dll           ← User, Role, Permission, Result
├── MyApp.Specifications.dll         ← IUserRolesSpec, IJwtRefreshSpec, validator bridges
├── MyApp.Domain.dll                 ← AuthorizationService : IUserRolesSpec
├── MyApp.Api.dll                    ← Controllers, DI wiring, startup compliance
└── MyApp.Tests.dll                  ← Type-linked tests (not deployed)

Generated at compile time (embedded in respective DLLs):
├── RequirementRegistry.g.cs         ← Type catalog + hierarchy
├── TraceabilityMatrix.g.cs          ← Requirement → Implementation → Test mapping
└── Compiler diagnostics             ← IDE warnings for untested ACs
⬇ Download