using Fitness_core_BE; using Fitness_core_BE.AI; using Fitness_core_BE.Auth; using Fitness_core_BE.Helpers; using Fitness_core_BE.Hubs; using Fitness_core_BE.Infra.UoW; using Fitness_core_BE.Interfaces; using Fitness_core_BE.Interfaces.Services; using Fitness_core_BE.Repos; using Fitness_core_BE.Services; using Fitness_core_BE.Services.ActivityLog; using Fitness_core_BE.Services.Auth; using Fitness_core_BE.Services.Chat; using Fitness_core_BE.Services.ClientInvoice; using Fitness_core_BE.Services.CustomerService; using Fitness_core_BE.Services.CustomerInvoice; using Fitness_core_BE.Services.Payment; using Fitness_core_BE.Services.CustomerPlanService; using Fitness_core_BE.Services.CustomerSubscription; using Fitness_core_BE.Services.Document; using Fitness_core_BE.Services.Feed; using Fitness_core_BE.Services.FunctionHandler; using Fitness_core_BE.Services.Meal; using Fitness_core_BE.Services.Staff; using Fitness_core_BE.Services.Ticket; using Fitness_core_BE.Services.Workout; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); QuestPDF.Settings.License = QuestPDF.Infrastructure.LicenseType.Community; // Add services to the container. builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles; }); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "Fitness Core Backend API", Version = "v1", Description = "API for managing fitness-related operations including ticket management system", Contact = new Microsoft.OpenApi.Models.OpenApiContact { Name = "Development Team", Email = "dev@fitness-core.com" } }); // Enable XML comments if available var xmlFile = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = System.IO.Path.Combine(AppContext.BaseDirectory, xmlFile); if (System.IO.File.Exists(xmlPath)) { options.IncludeXmlComments(xmlPath); } }); // AppDBContext is kept as inert legacy code (not deleted, per the non-destructive migration // principle) but is intentionally left unregistered -- CentralDbContext/TenantDbContext below // are what every repo/service now actually uses. builder.Services.AddHttpContextAccessor(); // Single club, single database -- both contexts share one connection string. (GYM's split // used CentralDbContext/TenantDbContext to route each request to one of many per-client MySQL // schemas; Vijaya has exactly one club, so that routing layer is gone and both contexts just // point at the same DB. The two C# context classes stay separate to avoid a much larger, // riskier refactor across every repo that injects one or the other.) builder.Services.AddDbContext(options => { options.UseMySql( builder.Configuration.GetConnectionString("DefaultConnection"), // Keep startup and EF tooling independent of database network availability. // This is the minimum supported MySQL baseline; Pomelo adjusts generated SQL. new MySqlServerVersion(new Version(8, 0, 0)) ); }); builder.Services.AddDbContext(options => { options.UseMySql( builder.Configuration.GetConnectionString("DefaultConnection"), new MySqlServerVersion(new Version(8, 0, 0)) ); }); builder.Services.AddCors(o => o.AddPolicy("AllowAll", p => p.SetIsOriginAllowed(origin => true) .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials() ) ); builder.Services.AddHttpClient(); builder.Services.AddScoped(); builder.Services.AddSignalR(); builder.Services.AddHttpContextAccessor(); // Register Repositories 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(); 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(); 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(); // Register Helpers builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Register Services 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(); 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(); 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(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Register Function Handlers 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(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Register AI Services builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddHttpClient(); // Register Access Device Service builder.Services.AddScoped(); builder.Services.AddScoped(); // Register Payment-Service clients: catalog/provisioning admin proxy (X-Internal-Key), // and the per-platform HMAC-signed client for real card/payment/refund calls. builder.Services.AddScoped(); builder.Services.AddScoped(); // Shared by background jobs that have no HttpContext to resolve a tenant from -- lets them // loop over every real, provisioned tenant schema directly instead of only ever seeing // whichever schema TenantConnectionResolver's request-based fallback resolves to. builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); // Auto-lock members after configurable days overdue (req 7) -- disabled at the user's request. // OverdueLockRunner (above) stays registered, so the manual "trigger now" endpoint // (POST api/admin/background-jobs/overdue-lock/trigger) still works on demand; only the // automatic startup + 6-hourly run is turned off. Uncomment to re-enable. // builder.Services.AddHostedService(); // Auto-renew expired subscriptions (new plan price + carried-over overdue balance) builder.Services.AddHostedService(); // Basic P&L / ledger for the client portal builder.Services.AddScoped(); // Register On-prem Agent platform builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Agent API-key authentication scheme + policy (does not affect existing admin/user auth). builder.Services .AddAuthentication() .AddScheme( AgentApiKeyDefaults.AuthenticationScheme, _ => { }) .AddScheme( UserJwtDefaults.AuthenticationScheme, _ => { }); builder.Services.AddAuthorization(options => { options.AddPolicy(AgentApiKeyDefaults.PolicyName, policy => { policy.AddAuthenticationSchemes(AgentApiKeyDefaults.AuthenticationScheme); policy.RequireAuthenticatedUser(); }); }); // Register Attendance Service builder.Services.AddScoped(); builder.Services.AddScoped(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // First in the pipeline so it catches anything thrown by everything after it. app.UseMiddleware(); app.UseRouting(); app.UseCors("AllowAll"); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.MapHub("/hubs/chat"); app.MapHub("/hubs/access"); app.Run();