using System.Text; using System.Text.Json.Serialization; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi; using Serilog; using UniVerse.Api.BackgroundServices; using UniVerse.Api.Middleware; using UniVerse.Application.Interfaces; using UniVerse.Infrastructure.Services; using UniVerse.Infrastructure.Data; using UniVerse.Infrastructure.ExternalServices; var builder = WebApplication.CreateBuilder(args); var useAspire = builder.Configuration.GetValue("Aspire:Enabled"); if (useAspire) { builder.AddServiceDefaults(); } // --- Serilog --- Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(builder.Configuration) .Enrich.FromLogContext() .WriteTo.Console() .CreateLogger(); builder.Host.UseSerilog(); // --- DbContext --- builder.Services.AddDbContext(options => { options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"), npgsql => { npgsql.EnableRetryOnFailure(3); npgsql.MigrationsAssembly("UniVerse.Infrastructure"); // Указывает EF Core, в какой сборке искать/хранить миграции. }); }); // --- Authentication --- builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Secret"]!)) }; }); builder.Services.AddAuthorization(); // --- CORS --- builder.Services.AddCors(options => { options.AddDefaultPolicy(policy => { policy.WithOrigins( builder.Configuration.GetSection("Cors:Origins").Get() ?? ["http://localhost:5173", "http://localhost:3000"]) .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); // --- Services DI --- builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // --- HTTP Clients --- builder.Services.AddHttpClient(client => { client.BaseAddress = new Uri(builder.Configuration["Llm:BaseUrl"] ?? "https://api.openai.com/v1/"); client.Timeout = TimeSpan.FromSeconds(60); }); builder.Services.AddHttpClient(client => { client.BaseAddress = new Uri(builder.Configuration["ModeusApi:BaseUrl"] ?? "https://schedule.rdcenter.ru"); client.Timeout = TimeSpan.FromSeconds(30); }); // --- Background Services --- builder.Services.AddHostedService(); // --- Controllers --- builder.Services.AddControllers() .AddJsonOptions(o => { o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); o.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; }); // --- Swagger --- builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "UniVerse API", Version = "v1", Description = "Universe" }); options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Name = "Authorization", Type = SecuritySchemeType.Http, Scheme = "bearer", BearerFormat = "JWT", In = ParameterLocation.Header, Description = "Enter your JWT token" }); options.AddSecurityRequirement(doc => { var bearerSchemeRef = new OpenApiSecuritySchemeReference("Bearer", doc, externalResource: null); return new OpenApiSecurityRequirement { [bearerSchemeRef] = new List() }; }); }); var app = builder.Build(); if (useAspire) { app.MapDefaultEndpoints(); } // --- Middleware Pipeline --- app.UseMiddleware(); app.UseMiddleware(); if (app.Environment.IsDevelopment()) { app.UseSwagger(c => { c.RouteTemplate = "api/docs/{documentName}/swagger.json"; }); app.UseSwaggerUI(c => { c.RoutePrefix = "api/docs"; c.SwaggerEndpoint("v1/swagger.json", "UniVerse API v1"); }); } app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();