feat(api): configure API application startup
This commit is contained in:
108
src/IncidentOps.Api/Program.cs
Normal file
108
src/IncidentOps.Api/Program.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System.Text;
|
||||
using FluentMigrator.Runner;
|
||||
using Hangfire;
|
||||
using Hangfire.Redis.StackExchange;
|
||||
using IncidentOps.Api.Auth;
|
||||
using IncidentOps.Infrastructure;
|
||||
using IncidentOps.Infrastructure.Auth;
|
||||
using IncidentOps.Infrastructure.Migrations;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using StackExchange.Redis;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add controllers
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
// Configure JWT settings
|
||||
var jwtSettings = new JwtSettings
|
||||
{
|
||||
Issuer = builder.Configuration["Jwt:Issuer"] ?? "incidentops",
|
||||
Audience = builder.Configuration["Jwt:Audience"] ?? "incidentops",
|
||||
SigningKey = builder.Configuration["Jwt:SigningKey"] ?? throw new InvalidOperationException("JWT signing key not configured"),
|
||||
AccessTokenExpirationMinutes = builder.Configuration.GetValue<int>("Jwt:AccessTokenExpirationMinutes", 15),
|
||||
RefreshTokenExpirationDays = builder.Configuration.GetValue<int>("Jwt:RefreshTokenExpirationDays", 7)
|
||||
};
|
||||
|
||||
// Configure Infrastructure
|
||||
var connectionString = builder.Configuration.GetConnectionString("Postgres")
|
||||
?? throw new InvalidOperationException("Postgres connection string not configured");
|
||||
builder.Services.AddInfrastructure(connectionString, jwtSettings);
|
||||
|
||||
// Configure FluentMigrator
|
||||
builder.Services.AddFluentMigratorCore()
|
||||
.ConfigureRunner(rb => rb
|
||||
.AddPostgres()
|
||||
.WithGlobalConnectionString(connectionString)
|
||||
.ScanIn(typeof(Migration0001_InitialSchema).Assembly).For.Migrations())
|
||||
.AddLogging(lb => lb.AddFluentMigratorConsole());
|
||||
|
||||
// Configure JWT Authentication
|
||||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = jwtSettings.Issuer,
|
||||
ValidAudience = jwtSettings.Audience,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SigningKey))
|
||||
};
|
||||
});
|
||||
|
||||
// Configure Authorization
|
||||
builder.Services.AddSingleton<IAuthorizationHandler, RoleRequirementHandler>();
|
||||
builder.Services.AddAuthorizationBuilder()
|
||||
.AddPolicy("Viewer", policy => policy.Requirements.Add(new RoleRequirement(IncidentOps.Domain.Enums.OrgRole.Viewer)))
|
||||
.AddPolicy("Member", policy => policy.Requirements.Add(new RoleRequirement(IncidentOps.Domain.Enums.OrgRole.Member)))
|
||||
.AddPolicy("Admin", policy => policy.Requirements.Add(new RoleRequirement(IncidentOps.Domain.Enums.OrgRole.Admin)));
|
||||
|
||||
// Configure Hangfire (client only - server runs in Worker)
|
||||
var redisConnectionString = builder.Configuration["Redis:ConnectionString"]
|
||||
?? throw new InvalidOperationException("Redis connection string not configured");
|
||||
builder.Services.AddHangfire(configuration => configuration
|
||||
.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
|
||||
.UseSimpleAssemblyNameTypeSerializer()
|
||||
.UseRecommendedSerializerSettings()
|
||||
.UseRedisStorage(ConnectionMultiplexer.Connect(redisConnectionString)));
|
||||
|
||||
// Add CORS
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddDefaultPolicy(policy =>
|
||||
{
|
||||
policy.WithOrigins(builder.Configuration.GetSection("Cors:Origins").Get<string[]>() ?? ["http://localhost:3000"])
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod()
|
||||
.AllowCredentials();
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Run migrations
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var runner = scope.ServiceProvider.GetRequiredService<IMigrationRunner>();
|
||||
runner.MigrateUp();
|
||||
}
|
||||
|
||||
// Configure the HTTP request pipeline
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
}
|
||||
|
||||
app.UseCors();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
Reference in New Issue
Block a user