Files
pos-system/services/ads-analytics-service-net/src/AdsAnalyticsService.API/Program.cs
Ho Ngoc Hai f8606e0447 fix(P0): security hardening + critical bug fixes across 22 services
Wave 1 — 6 parallel agents fixing P0 issues from code audit:

Auth (18 services secured):
- Added JWT Bearer auth + [Authorize] to all unprotected controllers
- Webhook endpoints (Facebook/WhatsApp/Zalo/X) stay [AllowAnonymous]
- Health checks remain public for Docker/K8s probes
- Services: catalog, order, booking, fnb-engine, inventory, social,
  ads-manager, ads-serving, ads-billing, ads-tracking, ads-analytics,
  mkt-facebook, mkt-whatsapp, mkt-x, mkt-zalo, promotion

Template artifacts (4 services):
- mission-service: myservice_db → mission_service
- mkt-facebook: Dockerfile MyService.API → FacebookService.API
- mkt-whatsapp: MyServiceContext.cs → WhatsAppServiceContext.cs
- promotion: UserSecretsId fixed

Critical handler bugs (7 fixes):
- ads-tracking: TrackPixelEventHandler now persists to DB
- ads-tracking: RecordConversion endpoint exposed via controller
- booking: UpdateResource now applies Name + Capacity changes
- ads-manager: ListPendingAds uses correct enum (pending_review)
- mining: BanMiner calls Ban() not Suspend()
- mining: ResetMinerStreak now actually resets streak
- mkt-x: 8 missing repository DI registrations added

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 20:18:09 +07:00

190 lines
6.8 KiB
C#

using Microsoft.EntityFrameworkCore;
using Asp.Versioning;
using FluentValidation;
using Hellang.Middleware.ProblemDetails;
using AdsAnalyticsService.API.Application.Behaviors;
using AdsAnalyticsService.Infrastructure;
using Serilog;
// EN: Configure Serilog early / VI: Cấu hình Serilog sớm
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateBootstrapLogger();
try
{
Log.Information("Starting AdsAnalyticsService API / Khởi động AdsAnalyticsService API");
var builder = WebApplication.CreateBuilder(args);
// EN: Configure Serilog / VI: Cấu hình Serilog
builder.Host.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext()
.WriteTo.Console());
// EN: Add Infrastructure services / VI: Thêm Infrastructure services
builder.Services.AddInfrastructure(builder.Configuration);
// EN: Add MediatR with behaviors / VI: Thêm MediatR với behaviors
builder.Services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssemblyContaining<Program>();
cfg.AddOpenBehavior(typeof(LoggingBehavior<,>));
cfg.AddOpenBehavior(typeof(ValidatorBehavior<,>));
cfg.AddOpenBehavior(typeof(TransactionBehavior<,>));
});
// EN: Add FluentValidation / VI: Thêm FluentValidation
builder.Services.AddValidatorsFromAssemblyContaining<Program>();
// EN: Add API versioning / VI: Thêm API versioning
builder.Services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("X-Api-Version"));
})
.AddApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
// EN: Add controllers / VI: Thêm controllers
builder.Services.AddControllers();
// EN: Add ProblemDetails middleware (RFC 7807) / VI: Thêm ProblemDetails middleware
builder.Services.AddProblemDetails(options =>
{
options.IncludeExceptionDetails = (ctx, ex) =>
builder.Environment.IsDevelopment();
});
// EN: Add Swagger / VI: Thêm Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new()
{
Title = "AdsAnalyticsService API",
Version = "v1",
Description = "AdsAnalyticsService microservice API / API microservice AdsAnalyticsService"
});
});
// EN: Add health checks / VI: Thêm health checks
builder.Services.AddHealthChecks()
.AddNpgSql(
builder.Configuration.GetConnectionString("DefaultConnection")
?? builder.Configuration["DATABASE_URL"]
?? "",
name: "postgresql",
tags: ["db", "postgresql"]);
// EN: Add JWT Bearer authentication via IAM IdentityServer OIDC discovery
// VI: Thêm JWT Bearer authentication qua IAM IdentityServer OIDC discovery
var jwtAuthority = builder.Configuration["Jwt:Authority"] ?? "http://localhost:5001";
builder.Services.AddAuthentication(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = jwtAuthority;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
// EN: In Development, skip signature validation to allow Docker IAM tokens
// VI: Trong Development, bỏ qua validate signature để chấp nhận token từ Docker IAM
ValidateIssuerSigningKey = builder.Environment.IsDevelopment() ? false : true,
SignatureValidator = builder.Environment.IsDevelopment()
? (token, _) => new Microsoft.IdentityModel.JsonWebTokens.JsonWebToken(token)
: null,
};
});
builder.Services.AddAuthorization();
// EN: Add CORS / VI: Thêm CORS
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
var app = builder.Build();
// EN: Configure middleware pipeline / VI: Cấu hình middleware pipeline
app.UseSerilogRequestLogging();
app.UseProblemDetails();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "AdsAnalyticsService API v1");
c.RoutePrefix = "swagger";
});
}
app.UseCors();
app.UseRouting();
// EN: Add authentication & authorization middleware / VI: Thêm middleware xác thực & phân quyền
app.UseAuthentication();
app.UseAuthorization();
// EN: Map health check endpoints (anonymous) / VI: Map health check endpoints (không cần xác thực)
app.MapHealthChecks("/health").AllowAnonymous();
app.MapHealthChecks("/health/live", new()
{
Predicate = _ => false // EN: Just checks app is running / VI: Chỉ kiểm tra app đang chạy
}).AllowAnonymous();
app.MapHealthChecks("/health/ready").AllowAnonymous();
// EN: Map controllers / VI: Map controllers
app.MapControllers();
// EN: Run the application / VI: Chạy ứng dụng
// EN: Auto-apply EF Core migrations on startup
// VI: Tự động áp dụng EF Core migrations khi khởi động
try
{
using (var scope = app.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<AdsAnalyticsServiceContext>();
await dbContext.Database.MigrateAsync();
}
}
catch (Exception ex)
{
// EN: Log migration errors but don't crash the app (e.g. PendingModelChangesWarning in EF Core 10)
// VI: Log lỗi migration nhưng không crash app
Console.WriteLine($"Warning: EF Core migration issue: {ex.Message}");
}
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application terminated unexpectedly / Ứng dụng kết thúc bất ngờ");
throw;
}
finally
{
Log.CloseAndFlush();
}
// EN: Make Program class accessible for integration tests
// VI: Làm cho class Program có thể truy cập cho integration tests
public partial class Program { }