From 895e40edc04019773d5e1a33085c379746f12d69 Mon Sep 17 00:00:00 2001 From: Manuel Date: Mon, 1 Sep 2025 22:25:21 +0200 Subject: [PATCH 1/3] inicio bases --- back/Program.cs | 105 ++++++++++++++++++ back/Properties/launchSettings.json | 15 +++ back/appsettings.Development.json | 8 ++ back/appsettings.Production.json | 8 ++ back/appsettings.Staging.json | 8 ++ back/appsettings.json | 9 ++ back/back.csproj | 48 ++++++++ back/back.sln | 25 +++++ back/configs/healthchecks.json | 15 +++ back/configs/serilog.json | 41 +++++++ .../uiux/paleta (1).png | Bin .../uiux/paleta (2).png | Bin 12 files changed, 282 insertions(+) create mode 100644 back/Program.cs create mode 100644 back/Properties/launchSettings.json create mode 100644 back/appsettings.Development.json create mode 100644 back/appsettings.Production.json create mode 100644 back/appsettings.Staging.json create mode 100644 back/appsettings.json create mode 100644 back/back.csproj create mode 100644 back/back.sln create mode 100644 back/configs/healthchecks.json create mode 100644 back/configs/serilog.json rename Captura de pantalla 2025-08-11 003208.png => docs/uiux/paleta (1).png (100%) rename Captura de pantalla 2025-08-11 003533.png => docs/uiux/paleta (2).png (100%) diff --git a/back/Program.cs b/back/Program.cs new file mode 100644 index 0000000..8dbf2df --- /dev/null +++ b/back/Program.cs @@ -0,0 +1,105 @@ +using MCVIngenieros.Healthchecks; +using OpenTelemetry.Logs; +using OpenTelemetry.Metrics; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; +using Scalar.AspNetCore; +using Serilog; + +namespace back; + +public class Program +{ + public static void Main(string[] args) + { + var configFiles = Path.Combine(AppContext.BaseDirectory, "configs"); + if (!Directory.Exists(configFiles)) + { + Directory.CreateDirectory(configFiles); + } + + var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"; + + var configurationBuilder = new ConfigurationBuilder() + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddJsonFile($"appsettings.{environment}.json", optional: false, reloadOnChange: true); + + var configs = Directory.GetFiles(configFiles, "*.json", SearchOption.AllDirectories); + foreach (var config in configs) + { + configurationBuilder.AddJsonFile(config, optional: true, reloadOnChange: true); + } + + var configuration = configurationBuilder.Build(); + + Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(configuration) + .MinimumLevel.Verbose() + .Enrich.FromLogContext() + .CreateLogger(); + + try + { + var builder = WebApplication.CreateBuilder(args); + builder.Configuration.AddConfiguration(configuration); + builder.Host.UseSerilog(); + // Add services to the container. + builder.Services.AddHealthChecksSupport().DiscoverHealthChecks(); + builder.Services.AddLogging(); + builder.Logging.AddOpenTelemetry(options => + { + options + .SetResourceBuilder( + ResourceBuilder.CreateDefault() + .AddService(AppDomain.CurrentDomain.FriendlyName)) + .AddConsoleExporter(); + }); + builder.Services.AddOpenTelemetry() + .ConfigureResource(resource => resource.AddService(AppDomain.CurrentDomain.FriendlyName)) + .WithTracing(tracing => tracing + .AddAspNetCoreInstrumentation() + .AddConsoleExporter()) + .WithMetrics(metrics => metrics + .AddAspNetCoreInstrumentation() + .AddConsoleExporter()); + + + + builder.Services.AddControllers(options => + { + options.Filters.Add(new Microsoft.AspNetCore.Mvc.RequireHttpsAttribute()); + }); + // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi + builder.Services.AddOpenApi(); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.MapOpenApi(); + app.MapScalarApiReference("/api-docs", opt => + { + opt.WithTitle("My API Documentation"); + }); + } + + app.UseHttpsRedirection(); + + app.UseAuthorization(); + + + app.MapControllers(); + + app.Run(); + } + catch (Exception ex) + { + Log.Fatal(ex, "Application start-up failed"); + } + finally + { + Log.CloseAndFlush(); + } + } +} diff --git a/back/Properties/launchSettings.json b/back/Properties/launchSettings.json new file mode 100644 index 0000000..acdfb46 --- /dev/null +++ b/back/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "api-docs", + "applicationUrl": "https://localhost:7157", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/back/appsettings.Development.json b/back/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/back/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/back/appsettings.Production.json b/back/appsettings.Production.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/back/appsettings.Production.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/back/appsettings.Staging.json b/back/appsettings.Staging.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/back/appsettings.Staging.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/back/appsettings.json b/back/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/back/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/back/back.csproj b/back/back.csproj new file mode 100644 index 0000000..bad8936 --- /dev/null +++ b/back/back.csproj @@ -0,0 +1,48 @@ + + + + net9.0 + enable + enable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/back/back.sln b/back/back.sln new file mode 100644 index 0000000..3b14fa6 --- /dev/null +++ b/back/back.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36401.2 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "back", "back.csproj", "{C78E8225-44D3-434B-AC2A-C8F4459BB18C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C78E8225-44D3-434B-AC2A-C8F4459BB18C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C78E8225-44D3-434B-AC2A-C8F4459BB18C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C78E8225-44D3-434B-AC2A-C8F4459BB18C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C78E8225-44D3-434B-AC2A-C8F4459BB18C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D5ABA005-3E91-4220-9B2C-874C0BED7E34} + EndGlobalSection +EndGlobal diff --git a/back/configs/healthchecks.json b/back/configs/healthchecks.json new file mode 100644 index 0000000..54fd253 --- /dev/null +++ b/back/configs/healthchecks.json @@ -0,0 +1,15 @@ +{ + "HealthChecksConfigs": { + "CacheDuration": "00:30:00", + "Timeout": "00:00:05", + "AssembliesToScan": [ + "back" + ] + //"MyCheck": { + // "RetryAttempts": 2, + // "Timeout": "00:05:00", + // "RetryDelay": "00:00:10", + // "Severity": "Info" + //} + } +} \ No newline at end of file diff --git a/back/configs/serilog.json b/back/configs/serilog.json new file mode 100644 index 0000000..d7e7e0b --- /dev/null +++ b/back/configs/serilog.json @@ -0,0 +1,41 @@ +{ + "Serilog": { + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.OpenTelemetry" ], + "MinimumLevel": { + "Default": "Information" + }, + "WriteTo": [ + { + "Name": "Console" + }, + { + "Name": "File", + "Args": { + "path": "Logs/log-.txt", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 31, + "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "OpenTelemetry", + "Args": { + "endpoint": "http://localhost:4317", + "protocol": "Grpc", + "resourceAttributes": { + "service.name": "back.mmorales.photo", + "deployment.environment": "development" + } + } + } + ], + "Enrich": [ + "FromLogContext", + "WithThreadId", + "WithProcessId", + "WithEnvironmentName" + ] + } +} diff --git a/Captura de pantalla 2025-08-11 003208.png b/docs/uiux/paleta (1).png similarity index 100% rename from Captura de pantalla 2025-08-11 003208.png rename to docs/uiux/paleta (1).png diff --git a/Captura de pantalla 2025-08-11 003533.png b/docs/uiux/paleta (2).png similarity index 100% rename from Captura de pantalla 2025-08-11 003533.png rename to docs/uiux/paleta (2).png From 09c211a0fe0b998937d99ced91fc5dfc29a45c77 Mon Sep 17 00:00:00 2001 From: Manuel Date: Mon, 1 Sep 2025 23:06:17 +0200 Subject: [PATCH 2/3] proyecto preparado para DDD + CQRS --- back/Domain/ApplicationDbContext.cs | 12 +++++++++ back/Domain/IEntity.cs | 14 ++++++++++ back/Program.cs | 40 +++++++++++++++++++++++++++-- back/appsettings.Development.json | 3 ++- back/appsettings.Production.json | 3 ++- back/appsettings.json | 8 +----- back/back.csproj | 24 ++++++++++++++++- 7 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 back/Domain/ApplicationDbContext.cs create mode 100644 back/Domain/IEntity.cs diff --git a/back/Domain/ApplicationDbContext.cs b/back/Domain/ApplicationDbContext.cs new file mode 100644 index 0000000..c2961e7 --- /dev/null +++ b/back/Domain/ApplicationDbContext.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore; + +namespace back.Domain; + +public class ApplicationDbContext : DbContext +{ + public ApplicationDbContext(DbContextOptions options) : base(options) + { + Database.EnsureCreated(); + Database.Migrate(); + } +} \ No newline at end of file diff --git a/back/Domain/IEntity.cs b/back/Domain/IEntity.cs new file mode 100644 index 0000000..7b8164e --- /dev/null +++ b/back/Domain/IEntity.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace back.Domain; + +public interface IEntity +{ + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + string Id + { + get; + set; + } +} \ No newline at end of file diff --git a/back/Program.cs b/back/Program.cs index 8dbf2df..c2cc34f 100644 --- a/back/Program.cs +++ b/back/Program.cs @@ -1,4 +1,8 @@ +using Autofac.Extensions.DependencyInjection; +using back.Domain; using MCVIngenieros.Healthchecks; +using MediatR.Extensions.FluentValidation.AspNetCore; +using Microsoft.EntityFrameworkCore; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; @@ -43,7 +47,15 @@ public class Program var builder = WebApplication.CreateBuilder(args); builder.Configuration.AddConfiguration(configuration); builder.Host.UseSerilog(); - // Add services to the container. + builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); + + builder.Services.AddMediatR(cfg => + { + cfg.RegisterServicesFromAssembly(typeof(Program).Assembly); + }); + + builder.Services.AddFluentValidation([typeof(Program).Assembly]); + builder.Services.AddHealthChecksSupport().DiscoverHealthChecks(); builder.Services.AddLogging(); builder.Logging.AddOpenTelemetry(options => @@ -63,7 +75,32 @@ public class Program .AddAspNetCoreInstrumentation() .AddConsoleExporter()); + builder.Services.AddDataProtection(); + builder.Services.AddCors(options => + { + options.AddDefaultPolicy(policy => + { + policy + .WithOrigins(builder.Configuration.GetSection("AllowedHosts").Get() ?? []) + .SetIsOriginAllowedToAllowWildcardSubdomains() + .SetPreflightMaxAge(TimeSpan.FromMinutes(10)) + .AllowCredentials() + .AllowAnyHeader() + .AllowAnyMethod(); + }); + }); + builder.Services.AddHttpContextAccessor(); + builder.Services.AddAntiforgery(options => + { + options.HeaderName = "X-XSRF-TOKEN"; + }); + + builder.Services.AddDbContext(opts => + { + var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); + opts.UseSqlite(connectionString); + }); builder.Services.AddControllers(options => { @@ -88,7 +125,6 @@ public class Program app.UseAuthorization(); - app.MapControllers(); app.Run(); diff --git a/back/appsettings.Development.json b/back/appsettings.Development.json index 0c208ae..10f68b8 100644 --- a/back/appsettings.Development.json +++ b/back/appsettings.Development.json @@ -4,5 +4,6 @@ "Default": "Information", "Microsoft.AspNetCore": "Warning" } - } + }, + "AllowedHosts": "*" } diff --git a/back/appsettings.Production.json b/back/appsettings.Production.json index 0c208ae..3b46298 100644 --- a/back/appsettings.Production.json +++ b/back/appsettings.Production.json @@ -4,5 +4,6 @@ "Default": "Information", "Microsoft.AspNetCore": "Warning" } - } + }, + "AllowedHosts": "mmorales.photo" } diff --git a/back/appsettings.json b/back/appsettings.json index 10f68b8..0db3279 100644 --- a/back/appsettings.json +++ b/back/appsettings.json @@ -1,9 +1,3 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*" + } diff --git a/back/back.csproj b/back/back.csproj index bad8936..7ea4bfc 100644 --- a/back/back.csproj +++ b/back/back.csproj @@ -7,12 +7,35 @@ + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + @@ -41,7 +64,6 @@ - From 0a2353d7380046d0ec65ec40ddcc27063b529d40 Mon Sep 17 00:00:00 2001 From: Manuel Date: Mon, 1 Sep 2025 23:14:57 +0200 Subject: [PATCH 3/3] =?UTF-8?q?a=C3=B1ade=20automapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Infrastructure/AutoMapperProfile.cs | 20 ++++++++++++++++++++ back/Program.cs | 9 +++++++++ 2 files changed, 29 insertions(+) create mode 100644 back/Infrastructure/AutoMapperProfile.cs diff --git a/back/Infrastructure/AutoMapperProfile.cs b/back/Infrastructure/AutoMapperProfile.cs new file mode 100644 index 0000000..7c11001 --- /dev/null +++ b/back/Infrastructure/AutoMapperProfile.cs @@ -0,0 +1,20 @@ +using AutoMapper; + +namespace back.Infrastructure; + +public class AutoMapperProfile : Profile +{ + public AutoMapperProfile() + { + //CreateMap() + // .ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.UserId)) + // .ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FirstName)) + // .ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.LastName)) + // .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email)) + // .ForMember(dest => dest.BirthYear, opt => opt.MapFrom(src => src.Birthday.Year)) + // .ForMember(dest => dest.BirthMonth, opt => opt.MapFrom(src => src.Birthday.Month)) + // .ForMember(dest => dest.BirthDay, opt => opt.MapFrom(src => src.Birthday.Day)) + // .ForMember(dest => dest.OccupationName, opt => opt.Ignore()) + + } +} diff --git a/back/Program.cs b/back/Program.cs index c2cc34f..ad6d266 100644 --- a/back/Program.cs +++ b/back/Program.cs @@ -1,5 +1,7 @@ using Autofac.Extensions.DependencyInjection; +using AutoMapper; using back.Domain; +using back.Infrastructure; using MCVIngenieros.Healthchecks; using MediatR.Extensions.FluentValidation.AspNetCore; using Microsoft.EntityFrameworkCore; @@ -55,6 +57,13 @@ public class Program }); builder.Services.AddFluentValidation([typeof(Program).Assembly]); + builder.Services.AddAutoMapper(opts => + { + opts.AddProfile(); + opts.AllowNullCollections = true; + opts.AllowNullDestinationValues = true; + opts.DestinationMemberNamingConvention = new PascalCaseNamingConvention(); + }); builder.Services.AddHealthChecksSupport().DiscoverHealthChecks(); builder.Services.AddLogging();