using Api.Clients.Ai; using Api.Clients.Ai.Contracts; using Api.Clients.Api; using Api.Clients.Api.Contracts; using CvMatcher.Data; using CvMatcher.Data.Repositories; using CvMatcher.Data.Repositories.Contracts; using Api.Services; using Api.Services.Contracts; using CvMatcher.Models.Settings; using CvSearch.Data; using Microsoft.EntityFrameworkCore; using MyAi.Data; using MyAi.Data.Services; using Refit; using Serilog; using Common.Settings; using StartupHelpers; using System.Reflection; StartupExtensions.LoadDotEnvFile(); const string ServiceName = "cv-matcher-api"; var appVersion = StartupExtensions.GetApplicationVersion(Assembly.GetExecutingAssembly()); try { var builder = WebApplication.CreateBuilder(args); builder.ConfigureJsonSerilog(ServiceName, appVersion); Log.Information("Starting {Service} version {AppVersion}", ServiceName, appVersion); builder.AddAzureKeyVaultIfConfigured(); builder.Services.Configure(builder.Configuration.GetSection("Database")); builder.Services.Configure(builder.Configuration.GetSection("RagApi")); builder.Services.Configure(builder.Configuration.GetSection("InternalApi")); builder.Services.Configure(builder.Configuration.GetSection("Ai")); builder.Services.Configure(builder.Configuration.GetSection("Matcher")); builder.Services.Configure(builder.Configuration.GetSection("JobSearch")); builder.Services.AddRefitClient() .ConfigureHttpClient((sp, c) => { var settings = sp.GetRequiredService>().Value; c.BaseAddress = new Uri(settings.BaseUrl.TrimEnd('/') + "/"); if (!string.IsNullOrWhiteSpace(settings.InternalApiKey)) { c.DefaultRequestHeaders.Add("X-Internal-Api-Key", settings.InternalApiKey); } }); builder.Services.AddScoped(); builder.Services.AddHttpClient(); builder.Services.AddHttpClient(); builder.Services.AddDbContext(options => { var configuration = builder.Configuration; var connectionString = builder.Services.GetConfiguredDbConnectionString(configuration); options.UseSqlServer(connectionString, sql => { sql.MigrationsHistoryTable(CvMatcherDbContext.MigrationTableName, CvMatcherDbContext.SchemaName); sql.MigrationsAssembly("cv-matcher-data"); }); }); builder.Services.AddDbContext(options => { var connectionString = builder.Services.GetConfiguredDbConnectionString(builder.Configuration); options.UseSqlServer(connectionString, sql => { sql.MigrationsAssembly("cv-search-data"); sql.MigrationsHistoryTable(CvSearchDbContext.MigrationTableName, CvSearchDbContext.SchemaName); }); }); builder.Services.AddDbContext(options => { var connectionString = builder.Services.GetConfiguredDbConnectionString(builder.Configuration); options.UseSqlServer(connectionString, sql => { sql.MigrationsAssembly("myai-data"); sql.MigrationsHistoryTable(MyAiDbContext.MigrationTableName, MyAiDbContext.SchemaName); }); }); builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddControllers(); builder.Services.AddSwaggerWithXmlComments(Assembly.GetExecutingAssembly(), ServiceName); var app = builder.Build(); app.LogStartupDiagnostics(ServiceName); using (var scope = app.Services.CreateScope()) { var repository = scope.ServiceProvider.GetRequiredService(); await repository.InitializeAsync(CancellationToken.None); } app.UseDefaultSerilogRequestLogging(); app.UseJsonExceptionHandler(ServiceName); app.UseInternalApiKeyProtection(); app.UseSwaggerInDevelopment(ServiceName, ServiceName); app.MapControllers(); Log.Information("Running EF Core migrations if any"); using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); db.Database.Migrate(); } using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); db.Database.Migrate(); } using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); db.Database.Migrate(); } Log.Information("{Service} startup complete", ServiceName); app.Run(); } catch (Exception ex) { Log.Fatal(ex, "{Service} terminated unexpectedly", ServiceName); } finally { Log.Information("Shutting down {Service}", ServiceName); Log.CloseAndFlush(); }