Files
UniVerse/backend/UniVerse.Api/Program.cs
T

159 lines
5.1 KiB
C#

using System.Text;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
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);
// --- Serilog ---
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();
builder.Host.UseSerilog();
// --- DbContext ---
builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"),
npgsql =>
{
npgsql.EnableRetryOnFailure(3);
npgsql.MigrationsAssembly("UniVerse.Infrastructure");
});
});
// --- 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"] ?? "default-dev-secret-key-change-in-production-32chars!!"))
};
});
builder.Services.AddAuthorization();
// --- CORS ---
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.WithOrigins(
builder.Configuration.GetSection("Cors:Origins").Get<string[]>()
?? ["http://localhost:5173", "http://localhost:3000"])
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
// --- Services DI ---
builder.Services.AddScoped<IAuthService, AuthService>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<ITagService, TagService>();
builder.Services.AddScoped<ILocationService, LocationService>();
builder.Services.AddScoped<ICourseService, CourseService>();
builder.Services.AddScoped<ILectureService, LectureService>();
builder.Services.AddScoped<IReviewService, ReviewService>();
builder.Services.AddScoped<IGamificationService, GamificationService>();
builder.Services.AddScoped<IAchievementService, AchievementService>();
builder.Services.AddScoped<ILlmAnalysisService, LlmAnalysisService>();
builder.Services.AddScoped<IScheduleSyncService, ScheduleSyncService>();
// --- HTTP Clients ---
builder.Services.AddHttpClient<ILlmClient, LlmClient>(client =>
{
client.BaseAddress = new Uri(builder.Configuration["Llm:BaseUrl"] ?? "https://api.openai.com/v1/");
client.Timeout = TimeSpan.FromSeconds(60);
});
builder.Services.AddHttpClient<IModeusApiClient, ModeusApiClient>(client =>
{
client.BaseAddress = new Uri(builder.Configuration["ModeusApi:BaseUrl"] ?? "https://schedule.rdcenter.ru");
client.Timeout = TimeSpan.FromSeconds(30);
});
// --- Background Services ---
builder.Services.AddHostedService<LlmProcessingBackgroundService>();
// --- 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 = "University schedule, reviews, and gamification platform"
});
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "Enter your JWT token"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
},
Array.Empty<string>()
}
});
});
var app = builder.Build();
// --- Middleware Pipeline ---
app.UseMiddleware<RequestLoggingMiddleware>();
app.UseMiddleware<ExceptionHandlingMiddleware>();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "UniVerse API v1"));
}
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();