mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-07-16 09:37:23 +00:00
Auth and Emails land together since Auth's registration/resend flows need Emails to exist first. Service.Auth's four services (Register, Login, Confirmation, Token) collapse into MediatR commands/queries in Features.Auth; TokenService stays as a slice-internal service since multiple handlers call it. Auth no longer references Emails directly — it sends SendRegistrationEmailCommand/SendResendConfirmationEmailCommand (defined in Shared.Application) which Features.Emails handles, so neither slice has a project reference on the other. Service.Emails' IEmailService becomes Features.Emails' IEmailDispatcher, simplified to take (firstName, email, token) instead of a full UserAccount since that's all it ever used. API.Specs' TestApiFactory/MockEmailService are updated to swap in the relocated interface. Also deletes Infrastructure.Repository now that Breweries, UserManagement, and Auth have all moved their repos out of it, and replaces the two now-dead docker-compose test services (repository.tests, service.auth.tests, both pointing at deleted Dockerfiles) with a single unit.tests service that runs every Features.*.Tests project via Dockerfile.tests.
116 lines
3.7 KiB
C#
116 lines
3.7 KiB
C#
using API.Core;
|
|
using API.Core.Authentication;
|
|
using Features.Auth.Controllers;
|
|
using Features.Auth.DependencyInjection;
|
|
using Features.Breweries.Controllers;
|
|
using Features.Breweries.DependencyInjection;
|
|
using Features.Emails.DependencyInjection;
|
|
using Features.Emails.Services;
|
|
using Features.UserManagement.Controllers;
|
|
using Features.UserManagement.DependencyInjection;
|
|
using FluentValidation;
|
|
using FluentValidation.AspNetCore;
|
|
using Infrastructure.Jwt;
|
|
using Infrastructure.Sql;
|
|
using Shared.Application.Behaviors;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// Global Exception Filter
|
|
builder.Services.AddControllers(options =>
|
|
{
|
|
options.Filters.Add<GlobalExceptionFilter>();
|
|
})
|
|
.AddApplicationPart(typeof(BreweryController).Assembly)
|
|
.AddApplicationPart(typeof(UserController).Assembly)
|
|
.AddApplicationPart(typeof(AuthController).Assembly);
|
|
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
builder.Services.AddSwaggerGen();
|
|
builder.Services.AddOpenApi();
|
|
|
|
// Add FluentValidation
|
|
builder.Services.AddValidatorsFromAssemblyContaining<Program>();
|
|
builder.Services.AddValidatorsFromAssembly(typeof(BreweryController).Assembly);
|
|
builder.Services.AddValidatorsFromAssembly(typeof(UserController).Assembly);
|
|
builder.Services.AddValidatorsFromAssembly(typeof(AuthController).Assembly);
|
|
builder.Services.AddFluentValidationAutoValidation();
|
|
|
|
// Add MediatR. Each Features.* slice's assembly is registered here as it's introduced;
|
|
// ValidationBehavior runs FluentValidation validators in the MediatR pipeline for command/query handlers.
|
|
builder.Services.AddMediatR(cfg =>
|
|
{
|
|
cfg.RegisterServicesFromAssemblyContaining<Program>();
|
|
cfg.RegisterServicesFromAssembly(typeof(BreweryController).Assembly);
|
|
cfg.RegisterServicesFromAssembly(typeof(UserController).Assembly);
|
|
cfg.RegisterServicesFromAssembly(typeof(AuthController).Assembly);
|
|
cfg.RegisterServicesFromAssembly(typeof(IEmailDispatcher).Assembly);
|
|
cfg.AddOpenBehavior(typeof(ValidationBehavior<,>));
|
|
});
|
|
|
|
// Add health checks
|
|
builder.Services.AddHealthChecks();
|
|
|
|
// Configure logging for container output
|
|
builder.Logging.ClearProviders();
|
|
builder.Logging.AddConsole();
|
|
if (!builder.Environment.IsProduction())
|
|
{
|
|
builder.Logging.AddDebug();
|
|
}
|
|
|
|
// Configure Dependency Injection -------------------------------------------------------------------------------------
|
|
|
|
builder.Services.AddSingleton<
|
|
ISqlConnectionFactory,
|
|
DefaultSqlConnectionFactory
|
|
>();
|
|
|
|
builder.Services.AddFeaturesBreweries();
|
|
builder.Services.AddFeaturesUserManagement();
|
|
builder.Services.AddFeaturesAuth();
|
|
builder.Services.AddFeaturesEmails();
|
|
|
|
// ITokenInfrastructure is registered here (not inside Features.Auth's own DI extension) because
|
|
// JwtAuthenticationHandler, a host-level auth middleware concern, also depends on it directly.
|
|
builder.Services.AddScoped<ITokenInfrastructure, JwtInfrastructure>();
|
|
|
|
// Register the exception filter
|
|
builder.Services.AddScoped<GlobalExceptionFilter>();
|
|
|
|
// Configure JWT Authentication
|
|
builder
|
|
.Services.AddAuthentication("JWT")
|
|
.AddScheme<JwtAuthenticationOptions, JwtAuthenticationHandler>(
|
|
"JWT",
|
|
options => { }
|
|
);
|
|
|
|
builder.Services.AddAuthorization();
|
|
|
|
var app = builder.Build();
|
|
|
|
app.UseSwagger();
|
|
app.UseSwaggerUI();
|
|
app.MapOpenApi();
|
|
|
|
app.UseHttpsRedirection();
|
|
|
|
app.UseAuthentication();
|
|
app.UseAuthorization();
|
|
|
|
// Health check endpoint (used by Docker health checks and orchestrators)
|
|
app.MapHealthChecks("/health");
|
|
|
|
app.MapControllers();
|
|
app.MapFallbackToController("Handle404", "NotFound");
|
|
|
|
// Graceful shutdown handling
|
|
var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
|
|
lifetime.ApplicationStopping.Register(() =>
|
|
{
|
|
app.Logger.LogInformation("Application is shutting down gracefully...");
|
|
});
|
|
|
|
app.Run();
|