diff --git a/README.md b/README.md
index 7a51ce0..a753ecd 100644
--- a/README.md
+++ b/README.md
@@ -64,6 +64,30 @@ docker-compose --env-file .env.docker up --build -d
## Monitoring Tools
Enable real‑time metrics, logs, and health checks for the application by following the step‑by‑step setup guide. [Click for Guide](dockerfiles/monitoring/GUIDE.md)
+## Migration
+
+1. **Install the EF Core CLI tool (dotnet-ef)**
+ ```bash
+ dotnet tool install --global dotnet-ef
+
+This command adds the EF Core command-line tools to your system globally.
+
+2. **Verify the installation**
+ ```bash
+ dotnet ef --version
+If you see a version number, the tool has been installed successfully.
+
+3. **Create a new migration**
+ ```bash
+ dotnet ef migrations add InitialMigration --context DataContext --project src/Infra
+- --context DataContext: Specifies which DbContext to use when generating the migration.
+- --project src/Infra: Specifies the project folder where the migration files will be created.
+
+4. **Apply the migration to the database**
+ ```bash
+ dotnet ef database update --context DataContext --project src/Infra
+This command applies the latest migration to the database.
+
## Deployment
Service may be in sleep mode on the first request. You may need to wait for a few seconds. [Live Demo Url](https://api-0oqs.onrender.com/scalar)
diff --git a/src/Api/Controllers/.gitkeep b/dockerfiles/postgres-cluster/pgpool/.gitkeep
similarity index 100%
rename from src/Api/Controllers/.gitkeep
rename to dockerfiles/postgres-cluster/pgpool/.gitkeep
diff --git a/dockerfiles/postgres-cluster/pgpool/pgpool.conf b/dockerfiles/postgres-cluster/pgpool/pgpool.conf
index 436bb72..a49fde5 100644
--- a/dockerfiles/postgres-cluster/pgpool/pgpool.conf
+++ b/dockerfiles/postgres-cluster/pgpool/pgpool.conf
@@ -511,7 +511,7 @@ sr_check_user = 'admin'
# Streaming replication check user
# This is necessary even if you disable streaming
# replication delay check by sr_check_period = 0
-sr_check_password = 'AESIdSY+WwYAncDcAca4aPcdg=='
+sr_check_password = 'AESQwC+qXIlBxY3DhcDQ5HExQ=='
# Password for streaming replication check user
# Leaving it empty will make Pgpool-II to first look for the
# Password in pool_passwd file before using the empty password
@@ -564,7 +564,7 @@ health_check_timeout = '10'
# 0 means no timeout
health_check_user = 'admin'
# Health check user
-health_check_password = 'AESIdSY+WwYAncDcAca4aPcdg=='
+health_check_password = 'AESQwC+qXIlBxY3DhcDQ5HExQ=='
# Password for health check user
# Leaving it empty will make Pgpool-II to first look for the
# Password in pool_passwd file before using the empty password
diff --git a/src/Api/Controllers/SampleController.cs b/src/Api/Controllers/SampleController.cs
new file mode 100644
index 0000000..5f7665d
--- /dev/null
+++ b/src/Api/Controllers/SampleController.cs
@@ -0,0 +1,117 @@
+namespace Api.Controllers
+{
+ using Asp.Versioning;
+ using Domain.Interfaces;
+ using Domain.Models.Request.Sample;
+ using Microsoft.AspNetCore.Mvc;
+
+ ///
+ /// Represents the sample controller.
+ ///
+ [ApiController]
+ [Route("sample")]
+ [Tags("sample")]
+ [ApiVersion("1.0")]
+ public class SampleController : ControllerBase
+ {
+ private readonly ISampleService sampleService;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The sample service.
+ public SampleController(ISampleService sampleService)
+ {
+ this.sampleService = sampleService ?? throw new ArgumentNullException(nameof(sampleService));
+ }
+
+ ///
+ /// Gets a samples.
+ ///
+ /// The sample response model.
+ [HttpGet]
+ public async Task Get()
+ {
+ var result = await this.sampleService.GetSamplesAsync(new GetSamplesRequestModel(), CancellationToken.None);
+ return this.Ok(result);
+ }
+
+ ///
+ /// Gets a sample by ID.
+ ///
+ /// The sample ID.
+ /// The sample response model.
+ [HttpGet("{id:guid}")]
+ public async Task Get(Guid id)
+ {
+ var result = await this.sampleService.GetSampleAsync(id, CancellationToken.None);
+ if (result == null)
+ {
+ return this.NotFound();
+ }
+
+ return this.Ok(result);
+ }
+
+ ///
+ /// Creates a new sample.
+ ///
+ /// The create sample request model.
+ /// The created sample response model.
+ [HttpPost]
+ public async Task Create([FromBody] CreateSampleRequestModel request)
+ {
+ if (request == null)
+ {
+ return this.BadRequest("Request cannot be null.");
+ }
+
+ var result = await this.sampleService.CreateSampleAsync(request, CancellationToken.None);
+ return this.CreatedAtAction(nameof(this.Get), new { id = result.Id }, result);
+ }
+
+ ///
+ /// Updates an existing sample.
+ ///
+ /// The update sample request model.
+ /// The updated sample response model.
+ [HttpPut]
+ public async Task Update([FromBody] UpdateSampleRequestModel request)
+ {
+ if (request == null || request.Id == Guid.Empty)
+ {
+ return this.BadRequest("Request cannot be null and ID must be provided.");
+ }
+
+ var result = await this.sampleService.UpdateSampleAsync(request, CancellationToken.None);
+ if (result == null)
+ {
+ return this.NotFound();
+ }
+
+ return this.Ok(result);
+ }
+
+ ///
+ /// Deletes a sample by ID.
+ ///
+ /// The sample ID.
+ /// A boolean indicating success or failure.
+ [HttpDelete("{id:guid}")]
+ public async Task Delete(Guid id)
+ {
+ if (id == Guid.Empty)
+ {
+ return this.BadRequest("ID must be provided.");
+ }
+
+ var result = await this.sampleService.DeleteSampleAsync(id, CancellationToken.None);
+ if (!result)
+ {
+ return this.NotFound();
+ }
+
+ return this.NoContent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Api/Controllers/V1/SampleController.cs b/src/Api/Controllers/V1/SampleController.cs
deleted file mode 100644
index 99ec6bc..0000000
--- a/src/Api/Controllers/V1/SampleController.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-namespace Api.Controllers.V1
-{
- using Asp.Versioning;
- using Domain.Entities;
- using Domain.Interfaces;
- using Microsoft.AspNetCore.Mvc;
-
- ///
- /// Represents the sample controller.
- ///
- [ApiController]
- [Route("sample")]
- [Tags("sample")]
- [ApiVersion("1.0")]
- public class SampleController : ControllerBase
- {
- private static readonly string[] Summaries = new[]
- {
- "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching",
- };
-
- private readonly IRepository repository;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The repository.
- public SampleController(IRepository repository)
- {
- this.repository = repository;
- }
-
- ///
- /// Gets the weather forecast.
- ///
- /// The weather forecast.
- [HttpGet]
- public async Task> Get()
- {
- this.repository.Add(new SampleEntity { Name = "Sample-1" });
- var result = await this.repository.ListAsync();
- var forecast = Enumerable.Range(1, 5).Select(index =>
- new WeatherForecast(
- DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
- Random.Shared.Next(-20, 55),
- Summaries[Random.Shared.Next(Summaries.Length)]))
- .ToArray();
- return forecast;
- }
- }
-}
diff --git a/src/Api/Controllers/V2/SampleController.cs b/src/Api/Controllers/V2/SampleController.cs
deleted file mode 100644
index 649a4f0..0000000
--- a/src/Api/Controllers/V2/SampleController.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-namespace Api.Controllers.V2
-{
- using Asp.Versioning;
- using Microsoft.AspNetCore.Mvc;
-
- ///
- /// Represents the sample controller.
- ///
- [ApiController]
- [Route("sample")]
- [Tags("sample")]
- [ApiVersion("2.0")]
- public class SampleController : ControllerBase
- {
- private static readonly string[] Summaries = new[]
- {
- "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching",
- };
-
- ///
- /// Gets the weather forecast.
- ///
- /// The weather forecast.
- [HttpGet]
- public IEnumerable Get()
- {
- var forecast = Enumerable.Range(1, 5).Select(index =>
- new WeatherForecast(
- DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
- Random.Shared.Next(-20, 55),
- Summaries[Random.Shared.Next(Summaries.Length)]))
- .ToArray();
- return forecast;
- }
- }
-}
diff --git a/src/Api/Mappings/.gitkeep b/src/Api/MappingProfiles/.gitkeep
similarity index 100%
rename from src/Api/Mappings/.gitkeep
rename to src/Api/MappingProfiles/.gitkeep
diff --git a/src/Api/MappingProfiles/SampleMappingProfile.cs b/src/Api/MappingProfiles/SampleMappingProfile.cs
new file mode 100644
index 0000000..13cd6fa
--- /dev/null
+++ b/src/Api/MappingProfiles/SampleMappingProfile.cs
@@ -0,0 +1,25 @@
+namespace Api.MappingProfiles
+{
+ using AutoMapper;
+ using Domain.Entities;
+ using Domain.Models.Request.Sample;
+ using Domain.Models.Response.Sample;
+
+ ///
+ /// AutoMapper profile for mapping between domain entities and response models.
+ ///
+ public class SampleProfile : Profile
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SampleProfile()
+ {
+ this.CreateMap();
+ this.CreateMap();
+ this.CreateMap();
+ this.CreateMap();
+ this.CreateMap();
+ }
+ }
+}
diff --git a/src/Api/Microservice.csproj b/src/Api/Microservice.csproj
index c46a509..8ee4870 100644
--- a/src/Api/Microservice.csproj
+++ b/src/Api/Microservice.csproj
@@ -18,6 +18,8 @@
$(NoWarn);SA1516
+ App-Development-Secrets
+
diff --git a/src/Api/Program.cs b/src/Api/Program.cs
index b80aa88..5e57787 100644
--- a/src/Api/Program.cs
+++ b/src/Api/Program.cs
@@ -1,9 +1,11 @@
#pragma warning disable SA1200 // Using directive should appear within a namespace declaration
using Api.Configurations;
+using Api.MappingProfiles;
using Api.Middlewares;
using Asp.Versioning;
using Asp.Versioning.Builder;
using Domain.Interfaces;
+using Domain.Services;
using Infra.Data;
using Infra.Repositories;
using Microsoft.EntityFrameworkCore;
@@ -18,8 +20,11 @@
builder.Services.AddControllers();
builder.Services
- .AddDbContext(opts => opts.UseInMemoryDatabase("DemoDb"))
- .AddScoped(typeof(IRepository<>), typeof(Repository<>));
+ .AddDbContext(opts => opts.UseNpgsql(builder.Configuration.GetConnectionString("PgpoolDb")))
+ .AddScoped(typeof(IRepository<>), typeof(Repository<>))
+ .AddScoped(typeof(ISampleService), typeof(SampleService));
+
+builder.Services.AddAutoMapper(typeof(SampleProfile).Assembly);
builder.Services.AddApiVersioning(options =>
{
@@ -82,7 +87,7 @@
.WithName("GetWeatherForecast")
.WithOpenApi()
.WithApiVersionSet(new ApiVersionSet(new ApiVersionSetBuilder(string.Empty), "weatherForecast"))
-.HasApiVersion(new ApiVersion(1, 0));
+.HasApiVersion(new ApiVersion(2, 0));
app.MapControllers();
app.MapMetrics();
diff --git a/src/Api/appsettings.Development.json b/src/Api/appsettings.Development.json
index 7a50c09..2f2906d 100644
--- a/src/Api/appsettings.Development.json
+++ b/src/Api/appsettings.Development.json
@@ -7,5 +7,8 @@
"Microsoft.AspNetCore": "Warning"
}
},
- "UseJsonFormat": false
+ "UseJsonFormat": false,
+ "ConnectionStrings": {
+ "PgpoolDb": ""
+ }
}
\ No newline at end of file
diff --git a/src/Domain/Domain.csproj b/src/Domain/Domain.csproj
index 99f72e9..7a0c42b 100644
--- a/src/Domain/Domain.csproj
+++ b/src/Domain/Domain.csproj
@@ -5,4 +5,7 @@
enable
enable
+
+
+
diff --git a/src/Domain/Interfaces/ISampleService.cs b/src/Domain/Interfaces/ISampleService.cs
new file mode 100644
index 0000000..5a731dd
--- /dev/null
+++ b/src/Domain/Interfaces/ISampleService.cs
@@ -0,0 +1,13 @@
+using Domain.Models.Request.Sample;
+using Domain.Models.Response.Sample;
+
+namespace Domain.Interfaces;
+
+public interface ISampleService
+{
+ Task CreateSampleAsync(CreateSampleRequestModel request, CancellationToken cancellationToken = default);
+ Task GetSamplesAsync(GetSamplesRequestModel request, CancellationToken cancellationToken = default);
+ Task UpdateSampleAsync(UpdateSampleRequestModel request, CancellationToken cancellationToken = default);
+ Task GetSampleAsync(Guid id, CancellationToken cancellationToken = default);
+ Task DeleteSampleAsync(Guid id, CancellationToken cancellationToken = default);
+}
diff --git a/src/Domain/Models/Request/Sample/CreateSampleRequestModel.cs b/src/Domain/Models/Request/Sample/CreateSampleRequestModel.cs
new file mode 100644
index 0000000..321e968
--- /dev/null
+++ b/src/Domain/Models/Request/Sample/CreateSampleRequestModel.cs
@@ -0,0 +1,6 @@
+namespace Domain.Models.Request.Sample;
+
+public class CreateSampleRequestModel
+{
+ public string? Name { get; set; }
+}
diff --git a/src/Domain/Models/Request/Sample/GetSamplesRequestModel.cs b/src/Domain/Models/Request/Sample/GetSamplesRequestModel.cs
new file mode 100644
index 0000000..b8d9965
--- /dev/null
+++ b/src/Domain/Models/Request/Sample/GetSamplesRequestModel.cs
@@ -0,0 +1,6 @@
+namespace Domain.Models.Request.Sample;
+
+public class GetSamplesRequestModel
+{
+ public string? Name { get; set; }
+}
diff --git a/src/Domain/Models/Request/Sample/UpdateSampleRequestModel.cs b/src/Domain/Models/Request/Sample/UpdateSampleRequestModel.cs
new file mode 100644
index 0000000..3fd763d
--- /dev/null
+++ b/src/Domain/Models/Request/Sample/UpdateSampleRequestModel.cs
@@ -0,0 +1,8 @@
+namespace Domain.Models.Request.Sample;
+
+public class UpdateSampleRequestModel
+{
+ public Guid Id { get; set; }
+
+ public string? Name { get; set; }
+}
diff --git a/src/Domain/Models/Response/Sample/CreateSampleResponseModel.cs b/src/Domain/Models/Response/Sample/CreateSampleResponseModel.cs
new file mode 100644
index 0000000..2ee9c2c
--- /dev/null
+++ b/src/Domain/Models/Response/Sample/CreateSampleResponseModel.cs
@@ -0,0 +1,9 @@
+namespace Domain.Models.Response.Sample;
+
+public class CreateSampleResponseModel
+{
+ public Guid Id { get; set; }
+ public string? Name { get; set; }
+ public DateTime CreatedAt { get; set; }
+ public DateTime UpdatedAt { get; set; }
+}
diff --git a/src/Domain/Models/Response/Sample/GetSampleResponseModel.cs b/src/Domain/Models/Response/Sample/GetSampleResponseModel.cs
new file mode 100644
index 0000000..e7afff6
--- /dev/null
+++ b/src/Domain/Models/Response/Sample/GetSampleResponseModel.cs
@@ -0,0 +1,12 @@
+namespace Domain.Models.Response.Sample;
+
+public class GetSampleResponseModel
+{
+ public Guid? Id { get; set; }
+
+ public string? Name { get; set; }
+
+ public DateTime? UpdatedAt { get; set; }
+
+ public DateTime? CreatedAt { get; set; }
+}
\ No newline at end of file
diff --git a/src/Domain/Models/Response/Sample/GetSamplesResponseModel.cs b/src/Domain/Models/Response/Sample/GetSamplesResponseModel.cs
new file mode 100644
index 0000000..47e747a
--- /dev/null
+++ b/src/Domain/Models/Response/Sample/GetSamplesResponseModel.cs
@@ -0,0 +1,6 @@
+namespace Domain.Models.Response.Sample;
+
+public class GetSamplesResponseModel
+{
+ public IList Samples { get; set; } = new List();
+}
diff --git a/src/Domain/Models/Response/Sample/UpdateSampleResponseModel.cs b/src/Domain/Models/Response/Sample/UpdateSampleResponseModel.cs
new file mode 100644
index 0000000..febcfa2
--- /dev/null
+++ b/src/Domain/Models/Response/Sample/UpdateSampleResponseModel.cs
@@ -0,0 +1,12 @@
+namespace Domain.Models.Response.Sample;
+
+public class UpdateSampleResponseModel
+{
+ public Guid Id { get; set; }
+
+ public string? Name { get; set; }
+
+ public DateTime? UpdatedAt { get; set; }
+
+ public DateTime? CreatedAt { get; set; }
+}
diff --git a/src/Domain/Services/SampleService.cs b/src/Domain/Services/SampleService.cs
new file mode 100644
index 0000000..ca07584
--- /dev/null
+++ b/src/Domain/Services/SampleService.cs
@@ -0,0 +1,69 @@
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using AutoMapper;
+using Domain.Entities;
+using Domain.Interfaces;
+using Domain.Models.Request.Sample;
+using Domain.Models.Response.Sample;
+
+namespace Domain.Services;
+
+public class SampleService : ISampleService
+{
+ private readonly IRepository _repository;
+ private readonly IMapper _mapper;
+
+ public SampleService(IRepository repository,
+ IMapper mapper)
+ {
+ _repository = repository;
+ _mapper = mapper;
+ }
+
+ public async Task GetSampleAsync(Guid id, CancellationToken cancellationToken = default)
+ {
+ var entity = await _repository.GetByIdAsync(id, cancellationToken);
+ return _mapper.Map(entity);
+ }
+
+ public async Task GetSamplesAsync(GetSamplesRequestModel request, CancellationToken cancellationToken = default)
+ {
+ Expression> predicate = e => true;
+ if (!string.IsNullOrEmpty(request.Name))
+ {
+ predicate = e => e.Name == request.Name;
+
+ }
+ var samples = await _repository.ListAsync(predicate, true, cancellationToken);
+ var response = new GetSamplesResponseModel
+ {
+ Samples = _mapper.Map>(samples)
+ };
+ return response;
+ }
+
+ public async Task CreateSampleAsync(CreateSampleRequestModel request, CancellationToken cancellationToken = default)
+ {
+ var entity = _mapper.Map(request);
+ var createdEntity = await _repository.AddAsync(entity, cancellationToken);
+ await _repository.SaveChangesAsync(cancellationToken);
+ return _mapper.Map(createdEntity);
+ }
+
+ public async Task UpdateSampleAsync(UpdateSampleRequestModel request, CancellationToken cancellationToken = default)
+ {
+ var entity = _mapper.Map(request);
+ var updatedEntity = _repository.Update(entity);
+ await _repository.SaveChangesAsync(cancellationToken);
+ return _mapper.Map(updatedEntity);
+ }
+
+ public async Task DeleteSampleAsync(Guid id, CancellationToken cancellationToken = default)
+ {
+ var entity = await _repository.GetByIdAsync(id, cancellationToken);
+ if (entity == null) return false;
+
+ _repository.Remove(entity);
+ return true && await _repository.SaveChangesAsync(cancellationToken) > 0;
+ }
+}
\ No newline at end of file
diff --git a/src/Infra/Data/DataContext.cs b/src/Infra/Data/DataContext.cs
index 53e89cd..6adf06d 100644
--- a/src/Infra/Data/DataContext.cs
+++ b/src/Infra/Data/DataContext.cs
@@ -15,5 +15,5 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
base.OnConfiguring(optionsBuilder);
}
- public virtual DbSet Products => Set();
+ public virtual DbSet Samples => Set();
}
\ No newline at end of file
diff --git a/src/Infra/Data/DataContextFactory.cs b/src/Infra/Data/DataContextFactory.cs
new file mode 100644
index 0000000..30b7d91
--- /dev/null
+++ b/src/Infra/Data/DataContextFactory.cs
@@ -0,0 +1,28 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Design;
+using Microsoft.Extensions.Configuration;
+
+namespace Infra.Data
+{
+ public class DataContextFactory : IDesignTimeDbContextFactory
+ {
+ public DataContext CreateDbContext(string[] args)
+ {
+ var infraRoot = Directory.GetCurrentDirectory();
+ var apiRoot = Path.GetFullPath(Path.Combine(infraRoot, "..", "Api"));
+
+ var configuration = new ConfigurationBuilder()
+ .SetBasePath(apiRoot)
+ .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+ .AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
+ .Build();
+
+ var connectionString = configuration.GetConnectionString("PgpoolDb");
+
+ var optionsBuilder = new DbContextOptionsBuilder();
+ optionsBuilder.UseNpgsql(connectionString);
+
+ return new DataContext(optionsBuilder.Options);
+ }
+ }
+}
diff --git a/src/Infra/Infra.csproj b/src/Infra/Infra.csproj
index 8a6bc7c..c7e6c11 100644
--- a/src/Infra/Infra.csproj
+++ b/src/Infra/Infra.csproj
@@ -16,11 +16,13 @@
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Infra/Migrations/20250606135347_InitialMigration.Designer.cs b/src/Infra/Migrations/20250606135347_InitialMigration.Designer.cs
new file mode 100644
index 0000000..d50af63
--- /dev/null
+++ b/src/Infra/Migrations/20250606135347_InitialMigration.Designer.cs
@@ -0,0 +1,51 @@
+//
+using System;
+using Infra.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Infra.Migrations
+{
+ [DbContext(typeof(DataContext))]
+ [Migration("20250606135347_InitialMigration")]
+ partial class InitialMigration
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.4")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Domain.Entities.SampleEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.ToTable("Samples");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Infra/Migrations/20250606135347_InitialMigration.cs b/src/Infra/Migrations/20250606135347_InitialMigration.cs
new file mode 100644
index 0000000..26fec34
--- /dev/null
+++ b/src/Infra/Migrations/20250606135347_InitialMigration.cs
@@ -0,0 +1,36 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Infra.Migrations
+{
+ ///
+ public partial class InitialMigration : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Samples",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Name = table.Column(type: "text", nullable: false),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Samples", x => x.Id);
+ });
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "Samples");
+ }
+ }
+}
diff --git a/src/Infra/Migrations/DataContextModelSnapshot.cs b/src/Infra/Migrations/DataContextModelSnapshot.cs
new file mode 100644
index 0000000..a29c4a2
--- /dev/null
+++ b/src/Infra/Migrations/DataContextModelSnapshot.cs
@@ -0,0 +1,48 @@
+//
+using System;
+using Infra.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Infra.Migrations
+{
+ [DbContext(typeof(DataContext))]
+ partial class DataContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.4")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Domain.Entities.SampleEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.ToTable("Samples");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}