Initial project setup with domain, UoW, and API structure

Added .gitignore, solution, and project files for .NET 10. Introduced AGENTS.md and PLAN.md for guidelines and planning. Implemented appsettings.json, launchSettings.json, and MySQL config. Created AppDBContext and all domain models with composite keys. Added IUnitOfWork and EFUnitOfWork. Structured feature folders for Region, Route, Vehicle, Store, Warehouse, and Order with DTOs, repositories, services, and controllers. Added initial EF Core migrations and sample HTTP request. Registered dependencies and enabled OpenAPI in development.
This commit is contained in:
Kalana B. Thilakarathna
2026-08-18 08:25:18 +05:30
commit ac3f34e4f3
56 changed files with 2796 additions and 0 deletions
@@ -0,0 +1,10 @@
namespace Distribution.Features.Vehicle;
public interface IVehicleRepository
{
Task<Models.Vehicle?> GetByIdAsync(Guid id);
Task<List<Models.Vehicle>> GetAllAsync();
Task AddAsync(Models.Vehicle entity);
void Update(Models.Vehicle entity);
void Remove(Models.Vehicle entity);
}
@@ -0,0 +1,40 @@
using Microsoft.AspNetCore.Mvc;
namespace Distribution.Features.Vehicle;
[ApiController]
[Route("api/vehicles")]
public class VehicleController(VehicleService service) : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetAll() =>
Ok(await service.GetAllAsync());
[HttpGet("{id:guid}")]
public async Task<IActionResult> GetById(Guid id)
{
var result = await service.GetByIdAsync(id);
return result is null ? NotFound() : Ok(result);
}
[HttpPost]
public async Task<IActionResult> Create(CreateVehicleRequest request, CancellationToken ct)
{
var result = await service.CreateAsync(request, ct);
return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
}
[HttpPut("{id:guid}")]
public async Task<IActionResult> Update(Guid id, UpdateVehicleRequest request, CancellationToken ct)
{
var result = await service.UpdateAsync(id, request, ct);
return result is null ? NotFound() : Ok(result);
}
[HttpDelete("{id:guid}")]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
{
var deleted = await service.DeleteAsync(id, ct);
return deleted ? NoContent() : NotFound();
}
}
@@ -0,0 +1,9 @@
using Distribution.Models;
namespace Distribution.Features.Vehicle;
public record CreateVehicleRequest(string RegNumber, string NumberPlate, VehicleType Type);
public record UpdateVehicleRequest(string RegNumber, string NumberPlate, VehicleType Type);
public record VehicleResponse(Guid Id, string RegNumber, string NumberPlate, VehicleType Type, bool IsActive, DateTime CreatedAt);
@@ -0,0 +1,25 @@
using Distribution.Data;
using Microsoft.EntityFrameworkCore;
namespace Distribution.Features.Vehicle;
public class VehicleRepository(AppDBContext context) : IVehicleRepository
{
public async Task<Models.Vehicle?> GetByIdAsync(Guid id) =>
await context.Vehicles.FindAsync(id);
public async Task<List<Models.Vehicle>> GetAllAsync() =>
await context.Vehicles.ToListAsync();
public async Task AddAsync(Models.Vehicle entity) =>
await context.Vehicles.AddAsync(entity);
public void Update(Models.Vehicle entity) =>
context.Vehicles.Update(entity);
public void Remove(Models.Vehicle entity)
{
entity.IsActive = false;
context.Vehicles.Update(entity);
}
}
@@ -0,0 +1,80 @@
using Distribution.Infra.UoW;
namespace Distribution.Features.Vehicle;
public class VehicleService(IVehicleRepository repo, IUnitOfWork uow)
{
public async Task<List<VehicleResponse>> GetAllAsync() =>
(await repo.GetAllAsync())
.Where(v => v.IsActive)
.Select(v => new VehicleResponse(v.Id, v.RegNumber, v.NumberPlate, v.Type, v.IsActive, v.CreatedAt))
.ToList();
public async Task<VehicleResponse?> GetByIdAsync(Guid id)
{
var vehicle = await repo.GetByIdAsync(id);
if (vehicle is null || !vehicle.IsActive) return null;
return new VehicleResponse(vehicle.Id, vehicle.RegNumber, vehicle.NumberPlate, vehicle.Type, vehicle.IsActive, vehicle.CreatedAt);
}
public async Task<VehicleResponse> CreateAsync(CreateVehicleRequest request, CancellationToken ct = default)
{
var vehicle = new Models.Vehicle
{
RegNumber = request.RegNumber,
NumberPlate = request.NumberPlate,
Type = request.Type
};
await uow.BeginAsync(ct);
try
{
await repo.AddAsync(vehicle);
await uow.CommitAsync(ct);
}
catch
{
await uow.RollbackAsync(ct);
throw;
}
return new VehicleResponse(vehicle.Id, vehicle.RegNumber, vehicle.NumberPlate, vehicle.Type, vehicle.IsActive, vehicle.CreatedAt);
}
public async Task<VehicleResponse?> UpdateAsync(Guid id, UpdateVehicleRequest request, CancellationToken ct = default)
{
var vehicle = await repo.GetByIdAsync(id);
if (vehicle is null || !vehicle.IsActive) return null;
vehicle.RegNumber = request.RegNumber;
vehicle.NumberPlate = request.NumberPlate;
vehicle.Type = request.Type;
await uow.BeginAsync(ct);
try
{
repo.Update(vehicle);
await uow.CommitAsync(ct);
}
catch
{
await uow.RollbackAsync(ct);
throw;
}
return new VehicleResponse(vehicle.Id, vehicle.RegNumber, vehicle.NumberPlate, vehicle.Type, vehicle.IsActive, vehicle.CreatedAt);
}
public async Task<bool> DeleteAsync(Guid id, CancellationToken ct = default)
{
var vehicle = await repo.GetByIdAsync(id);
if (vehicle is null || !vehicle.IsActive) return false;
await uow.BeginAsync(ct);
try
{
repo.Remove(vehicle);
await uow.CommitAsync(ct);
}
catch
{
await uow.RollbackAsync(ct);
throw;
}
return true;
}
}