feat: Add functional tests for OrderService and update InventoryService command and idempotency logic.
This commit is contained in:
@@ -1,72 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
# EN: Docker Compose for local development
|
||||
# VI: Docker Compose cho phát triển local
|
||||
|
||||
services:
|
||||
myservice-api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: myservice-api
|
||||
ports:
|
||||
- "5000:8080"
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- DATABASE_URL=Host=postgres;Port=5432;Database=myservice_db;Username=postgres;Password=postgres
|
||||
- REDIS_URL=redis:6379
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- myservice-network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health/live"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: myservice-postgres
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: myservice_db
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- myservice-network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: myservice-redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- myservice-network
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
|
||||
networks:
|
||||
myservice-network:
|
||||
driver: bridge
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Diagnostics;
|
||||
using MediatR;
|
||||
|
||||
namespace MyService.API.Application.Behaviors;
|
||||
namespace FnbEngine.API.Application.Behaviors;
|
||||
|
||||
/// <summary>
|
||||
/// EN: MediatR behavior for logging request handling.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MyService.Infrastructure;
|
||||
using FnbEngine.Infrastructure;
|
||||
|
||||
namespace MyService.API.Application.Behaviors;
|
||||
namespace FnbEngine.API.Application.Behaviors;
|
||||
|
||||
/// <summary>
|
||||
/// EN: MediatR behavior for handling database transactions.
|
||||
@@ -13,11 +13,11 @@ namespace MyService.API.Application.Behaviors;
|
||||
public class TransactionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : IRequest<TResponse>
|
||||
{
|
||||
private readonly MyServiceContext _dbContext;
|
||||
private readonly FnbEngineContext _dbContext;
|
||||
private readonly ILogger<TransactionBehavior<TRequest, TResponse>> _logger;
|
||||
|
||||
public TransactionBehavior(
|
||||
MyServiceContext dbContext,
|
||||
FnbEngineContext dbContext,
|
||||
ILogger<TransactionBehavior<TRequest, TResponse>> logger)
|
||||
{
|
||||
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using FluentValidation;
|
||||
using MediatR;
|
||||
|
||||
namespace MyService.API.Application.Behaviors;
|
||||
namespace FnbEngine.API.Application.Behaviors;
|
||||
|
||||
/// <summary>
|
||||
/// EN: MediatR behavior for FluentValidation integration.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MediatR;
|
||||
|
||||
namespace MyService.API.Application.Commands;
|
||||
namespace FnbEngine.API.Application.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Command to change status of a Sample.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using MediatR;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
namespace MyService.API.Application.Commands;
|
||||
namespace FnbEngine.API.Application.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Handler for ChangeSampleStatusCommand.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MediatR;
|
||||
|
||||
namespace MyService.API.Application.Commands;
|
||||
namespace FnbEngine.API.Application.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Command to create a new Sample.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using MediatR;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
namespace MyService.API.Application.Commands;
|
||||
namespace FnbEngine.API.Application.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Handler for CreateSampleCommand.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MediatR;
|
||||
|
||||
namespace MyService.API.Application.Commands;
|
||||
namespace FnbEngine.API.Application.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Command to delete a Sample.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using MediatR;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
namespace MyService.API.Application.Commands;
|
||||
namespace FnbEngine.API.Application.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Handler for DeleteSampleCommand.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MediatR;
|
||||
|
||||
namespace MyService.API.Application.Commands;
|
||||
namespace FnbEngine.API.Application.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Command to update an existing Sample.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using MediatR;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
namespace MyService.API.Application.Commands;
|
||||
namespace FnbEngine.API.Application.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Handler for UpdateSampleCommand.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MediatR;
|
||||
|
||||
namespace MyService.API.Application.Queries;
|
||||
namespace FnbEngine.API.Application.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Query to get a Sample by ID.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using MediatR;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
namespace MyService.API.Application.Queries;
|
||||
namespace FnbEngine.API.Application.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Handler for GetSampleQuery.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MediatR;
|
||||
|
||||
namespace MyService.API.Application.Queries;
|
||||
namespace FnbEngine.API.Application.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Query to get all Samples.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using MediatR;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
namespace MyService.API.Application.Queries;
|
||||
namespace FnbEngine.API.Application.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Handler for GetSamplesQuery.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using FluentValidation;
|
||||
using MyService.API.Application.Commands;
|
||||
using FnbEngine.API.Application.Commands;
|
||||
|
||||
namespace MyService.API.Application.Validations;
|
||||
namespace FnbEngine.API.Application.Validations;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Validator for CreateSampleCommand.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using FluentValidation;
|
||||
using MyService.API.Application.Commands;
|
||||
using FnbEngine.API.Application.Commands;
|
||||
|
||||
namespace MyService.API.Application.Validations;
|
||||
namespace FnbEngine.API.Application.Validations;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Validator for UpdateSampleCommand.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using Asp.Versioning;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MyService.API.Application.Commands;
|
||||
using MyService.API.Application.Queries;
|
||||
using FnbEngine.API.Application.Commands;
|
||||
using FnbEngine.API.Application.Queries;
|
||||
|
||||
namespace MyService.API.Controllers;
|
||||
namespace FnbEngine.API.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Controller for Sample CRUD operations using CQRS pattern.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>MyService.API</AssemblyName>
|
||||
<RootNamespace>MyService.API</RootNamespace>
|
||||
<AssemblyName>FnbEngine.API</AssemblyName>
|
||||
<RootNamespace>FnbEngine.API</RootNamespace>
|
||||
<Description>Web API layer with CQRS pattern</Description>
|
||||
<UserSecretsId>myservice-api</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
@@ -36,8 +36,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MyService.Domain\MyService.Domain.csproj" />
|
||||
<ProjectReference Include="..\MyService.Infrastructure\MyService.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\FnbEngine.Domain\FnbEngine.Domain.csproj" />
|
||||
<ProjectReference Include="..\FnbEngine.Infrastructure\FnbEngine.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Asp.Versioning;
|
||||
using FluentValidation;
|
||||
using Hellang.Middleware.ProblemDetails;
|
||||
using MyService.API.Application.Behaviors;
|
||||
using MyService.Infrastructure;
|
||||
using FnbEngine.API.Application.Behaviors;
|
||||
using FnbEngine.Infrastructure;
|
||||
using Serilog;
|
||||
|
||||
// EN: Configure Serilog early / VI: Cấu hình Serilog sớm
|
||||
@@ -12,7 +12,7 @@ Log.Logger = new LoggerConfiguration()
|
||||
|
||||
try
|
||||
{
|
||||
Log.Information("Starting MyService API / Khởi động MyService API");
|
||||
Log.Information("Starting FnbEngine API / Khởi động FnbEngine API");
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@@ -70,9 +70,9 @@ try
|
||||
{
|
||||
options.SwaggerDoc("v1", new()
|
||||
{
|
||||
Title = "MyService API",
|
||||
Title = "FnbEngine API",
|
||||
Version = "v1",
|
||||
Description = "MyService microservice API / API microservice MyService"
|
||||
Description = "FnbEngine microservice API / API microservice FnbEngine"
|
||||
});
|
||||
});
|
||||
|
||||
@@ -107,7 +107,7 @@ try
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyService API v1");
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "FnbEngine API v1");
|
||||
c.RoutePrefix = "swagger";
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// EN: Kitchen ticket entity for kitchen display.
|
||||
// VI: Entity KitchenTicket cho hiển thị bếp.
|
||||
|
||||
using FnbEngine.Domain.SeedWork;
|
||||
|
||||
namespace FnbEngine.Domain.AggregatesModel.KitchenAggregate;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Kitchen ticket entity - represents an order item in the kitchen.
|
||||
/// VI: Entity KitchenTicket - đại diện cho item đơn hàng trong bếp.
|
||||
/// </summary>
|
||||
public class KitchenTicket : Entity, IAggregateRoot
|
||||
{
|
||||
private Guid _sessionId;
|
||||
private Guid _orderItemId;
|
||||
private string _itemName = null!;
|
||||
private string? _station; // Bar, Kitchen, Grill, etc.
|
||||
private int _priority;
|
||||
private string _status = null!; // Pending, InProgress, Ready, Served
|
||||
private DateTime _createdAt;
|
||||
private DateTime? _completedAt;
|
||||
|
||||
public Guid SessionId => _sessionId;
|
||||
public Guid OrderItemId => _orderItemId;
|
||||
public string ItemName => _itemName;
|
||||
public string? Station => _station;
|
||||
public int Priority => _priority;
|
||||
public string Status => _status;
|
||||
public DateTime CreatedAt => _createdAt;
|
||||
public DateTime? CompletedAt => _completedAt;
|
||||
|
||||
protected KitchenTicket()
|
||||
{
|
||||
}
|
||||
|
||||
public KitchenTicket(Guid sessionId, Guid orderItemId, string itemName, string? station = null, int priority = 0)
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
_sessionId = sessionId;
|
||||
_orderItemId = orderItemId;
|
||||
_itemName = itemName;
|
||||
_station = station;
|
||||
_priority = priority;
|
||||
_status = "Pending";
|
||||
_createdAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public void MarkAsInProgress()
|
||||
{
|
||||
_status = "InProgress";
|
||||
}
|
||||
|
||||
public void MarkAsReady()
|
||||
{
|
||||
_status = "Ready";
|
||||
_completedAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public void MarkAsServed()
|
||||
{
|
||||
_status = "Served";
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using MyService.Domain.SeedWork;
|
||||
using FnbEngine.Domain.SeedWork;
|
||||
|
||||
namespace MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
namespace FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Repository interface for Sample aggregate.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using MyService.Domain.Events;
|
||||
using MyService.Domain.Exceptions;
|
||||
using MyService.Domain.SeedWork;
|
||||
using FnbEngine.Domain.Events;
|
||||
using FnbEngine.Domain.Exceptions;
|
||||
using FnbEngine.Domain.SeedWork;
|
||||
|
||||
namespace MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
namespace FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Sample aggregate root demonstrating DDD patterns.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MyService.Domain.SeedWork;
|
||||
using FnbEngine.Domain.SeedWork;
|
||||
|
||||
namespace MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
namespace FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Sample status enumeration following type-safe enum pattern.
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// EN: Session entity for dining sessions.
|
||||
// VI: Entity Session cho phiên ăn uống.
|
||||
|
||||
using FnbEngine.Domain.Exceptions;
|
||||
using FnbEngine.Domain.SeedWork;
|
||||
|
||||
namespace FnbEngine.Domain.AggregatesModel.SessionAggregate;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Session entity - represents a dining session at a table.
|
||||
/// VI: Entity Session - đại diện cho phiên ăn tại bàn.
|
||||
/// </summary>
|
||||
public class Session : Entity, IAggregateRoot
|
||||
{
|
||||
private Guid _tableId;
|
||||
private Guid _shopId;
|
||||
private int _guestCount;
|
||||
private DateTime _startedAt;
|
||||
private DateTime? _closedAt;
|
||||
private string _status = null!; // Active, Closed
|
||||
|
||||
public Guid TableId => _tableId;
|
||||
public Guid ShopId => _shopId;
|
||||
public int GuestCount => _guestCount;
|
||||
public DateTime StartedAt => _startedAt;
|
||||
public DateTime? ClosedAt => _closedAt;
|
||||
public string Status => _status;
|
||||
|
||||
protected Session()
|
||||
{
|
||||
}
|
||||
|
||||
public Session(Guid tableId, Guid shopId, int guestCount = 1)
|
||||
{
|
||||
if (tableId == Guid.Empty)
|
||||
throw new DomainException("Table ID cannot be empty");
|
||||
if (shopId == Guid.Empty)
|
||||
throw new DomainException("Shop ID cannot be empty");
|
||||
if (guestCount <= 0)
|
||||
throw new DomainException("Guest count must be greater than zero");
|
||||
|
||||
Id = Guid.NewGuid();
|
||||
_tableId = tableId;
|
||||
_shopId = shopId;
|
||||
_guestCount = guestCount;
|
||||
_startedAt = DateTime.UtcNow;
|
||||
_status = "Active";
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (_status == "Closed")
|
||||
throw new DomainException("Session is already closed");
|
||||
|
||||
_closedAt = DateTime.UtcNow;
|
||||
_status = "Closed";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// EN: Table aggregate root for FnB.
|
||||
// VI: Aggregate root Table cho FnB.
|
||||
|
||||
using FnbEngine.Domain.Exceptions;
|
||||
using FnbEngine.Domain.SeedWork;
|
||||
|
||||
namespace FnbEngine.Domain.AggregatesModel.TableAggregate;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Table aggregate root - represents a dining table.
|
||||
/// VI: Aggregate root Table - đại diện cho bàn ăn.
|
||||
/// </summary>
|
||||
public class Table : Entity, IAggregateRoot
|
||||
{
|
||||
private Guid _shopId;
|
||||
private string _tableNumber = null!;
|
||||
private int _capacity;
|
||||
private string? _zone;
|
||||
private TableStatus _status = null!;
|
||||
private DateTime _createdAt;
|
||||
private DateTime? _updatedAt;
|
||||
|
||||
public Guid ShopId => _shopId;
|
||||
public string TableNumber => _tableNumber;
|
||||
public int Capacity => _capacity;
|
||||
public string? Zone => _zone;
|
||||
public TableStatus Status => _status;
|
||||
public int StatusId { get; private set; }
|
||||
public DateTime CreatedAt => _createdAt;
|
||||
public DateTime? UpdatedAt => _updatedAt;
|
||||
|
||||
protected Table()
|
||||
{
|
||||
}
|
||||
|
||||
public Table(Guid shopId, string tableNumber, int capacity, string? zone = null)
|
||||
{
|
||||
if (shopId == Guid.Empty)
|
||||
throw new DomainException("Shop ID cannot be empty");
|
||||
if (string.IsNullOrWhiteSpace(tableNumber))
|
||||
throw new DomainException("Table number cannot be empty");
|
||||
if (capacity <= 0)
|
||||
throw new DomainException("Capacity must be greater than zero");
|
||||
|
||||
Id = Guid.NewGuid();
|
||||
_shopId = shopId;
|
||||
_tableNumber = tableNumber.Trim();
|
||||
_capacity = capacity;
|
||||
_zone = zone?.Trim();
|
||||
_status = TableStatus.Available;
|
||||
StatusId = TableStatus.Available.Id;
|
||||
_createdAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public void MarkAsOccupied()
|
||||
{
|
||||
if (_status != TableStatus.Available && _status != TableStatus.Reserved)
|
||||
throw new DomainException($"Cannot occupy table with status {_status.Name}");
|
||||
|
||||
_status = TableStatus.Occupied;
|
||||
StatusId = TableStatus.Occupied.Id;
|
||||
_updatedAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public void MarkAsAvailable()
|
||||
{
|
||||
_status = TableStatus.Available;
|
||||
StatusId = TableStatus.Available.Id;
|
||||
_updatedAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public void MarkAsCleaning()
|
||||
{
|
||||
_status = TableStatus.Cleaning;
|
||||
StatusId = TableStatus.Cleaning.Id;
|
||||
_updatedAt = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// EN: Table status enumeration for FnB.
|
||||
// VI: Enumeration trạng thái bàn cho FnB.
|
||||
|
||||
using FnbEngine.Domain.SeedWork;
|
||||
|
||||
namespace FnbEngine.Domain.AggregatesModel.TableAggregate;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Table status enumeration.
|
||||
/// VI: Enumeration trạng thái bàn.
|
||||
/// </summary>
|
||||
public class TableStatus : Enumeration
|
||||
{
|
||||
public static readonly TableStatus Available = new(1, nameof(Available));
|
||||
public static readonly TableStatus Occupied = new(2, nameof(Occupied));
|
||||
public static readonly TableStatus Reserved = new(3, nameof(Reserved));
|
||||
public static readonly TableStatus Cleaning = new(4, nameof(Cleaning));
|
||||
|
||||
public TableStatus(int id, string name) : base(id, name)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using MediatR;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
namespace MyService.Domain.Events;
|
||||
namespace FnbEngine.Domain.Events;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Domain event raised when a new Sample is created.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using MediatR;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
namespace MyService.Domain.Events;
|
||||
namespace FnbEngine.Domain.Events;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Domain event raised when Sample status changes.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MyService.Domain.Exceptions;
|
||||
namespace FnbEngine.Domain.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Base exception for domain errors.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MyService.Domain.Exceptions;
|
||||
namespace FnbEngine.Domain.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Exception for Sample aggregate domain errors.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>MyService.Domain</AssemblyName>
|
||||
<RootNamespace>MyService.Domain</RootNamespace>
|
||||
<AssemblyName>FnbEngine.Domain</AssemblyName>
|
||||
<RootNamespace>FnbEngine.Domain</RootNamespace>
|
||||
<Description>Domain layer containing core business logic and entities</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MediatR;
|
||||
|
||||
namespace MyService.Domain.SeedWork;
|
||||
namespace FnbEngine.Domain.SeedWork;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Base class for all domain entities.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace MyService.Domain.SeedWork;
|
||||
namespace FnbEngine.Domain.SeedWork;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Base class for enumeration classes (type-safe enum pattern).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MyService.Domain.SeedWork;
|
||||
namespace FnbEngine.Domain.SeedWork;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Marker interface for aggregate roots.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MyService.Domain.SeedWork;
|
||||
namespace FnbEngine.Domain.SeedWork;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Generic repository interface for aggregate roots.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MyService.Domain.SeedWork;
|
||||
namespace FnbEngine.Domain.SeedWork;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Unit of Work pattern interface.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MyService.Domain.SeedWork;
|
||||
namespace FnbEngine.Domain.SeedWork;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Base class for Value Objects following DDD patterns.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using MyService.Infrastructure.Idempotency;
|
||||
using MyService.Infrastructure.Repositories;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Infrastructure.Idempotency;
|
||||
using FnbEngine.Infrastructure.Repositories;
|
||||
|
||||
namespace MyService.Infrastructure;
|
||||
namespace FnbEngine.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Dependency injection extensions for Infrastructure layer.
|
||||
@@ -22,7 +22,7 @@ public static class DependencyInjection
|
||||
IConfiguration configuration)
|
||||
{
|
||||
// EN: Add DbContext with PostgreSQL / VI: Thêm DbContext với PostgreSQL
|
||||
services.AddDbContext<MyServiceContext>(options =>
|
||||
services.AddDbContext<FnbEngineContext>(options =>
|
||||
{
|
||||
var connectionString = configuration.GetConnectionString("DefaultConnection")
|
||||
?? configuration["DATABASE_URL"]
|
||||
@@ -30,7 +30,7 @@ public static class DependencyInjection
|
||||
|
||||
options.UseNpgsql(connectionString, npgsqlOptions =>
|
||||
{
|
||||
npgsqlOptions.MigrationsAssembly(typeof(MyServiceContext).Assembly.FullName);
|
||||
npgsqlOptions.MigrationsAssembly(typeof(FnbEngineContext).Assembly.FullName);
|
||||
npgsqlOptions.EnableRetryOnFailure(
|
||||
maxRetryCount: 5,
|
||||
maxRetryDelay: TimeSpan.FromSeconds(30),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
namespace MyService.Infrastructure.EntityConfigurations;
|
||||
namespace FnbEngine.Infrastructure.EntityConfigurations;
|
||||
|
||||
/// <summary>
|
||||
/// EN: EF Core configuration for Sample entity.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
|
||||
namespace MyService.Infrastructure.EntityConfigurations;
|
||||
namespace FnbEngine.Infrastructure.EntityConfigurations;
|
||||
|
||||
/// <summary>
|
||||
/// EN: EF Core configuration for SampleStatus enumeration.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>MyService.Infrastructure</AssemblyName>
|
||||
<RootNamespace>MyService.Infrastructure</RootNamespace>
|
||||
<AssemblyName>FnbEngine.Infrastructure</AssemblyName>
|
||||
<RootNamespace>FnbEngine.Infrastructure</RootNamespace>
|
||||
<Description>Infrastructure layer for data access and external services</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MyService.Domain\MyService.Domain.csproj" />
|
||||
<ProjectReference Include="..\FnbEngine.Domain\FnbEngine.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MyService.Infrastructure.Idempotency;
|
||||
namespace FnbEngine.Infrastructure.Idempotency;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Entity for tracking client requests to ensure idempotency.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace MyService.Infrastructure.Idempotency;
|
||||
namespace FnbEngine.Infrastructure.Idempotency;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Interface for managing client request idempotency.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace MyService.Infrastructure.Idempotency;
|
||||
namespace FnbEngine.Infrastructure.Idempotency;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Implementation of request manager for idempotency.
|
||||
@@ -8,9 +8,9 @@ namespace MyService.Infrastructure.Idempotency;
|
||||
/// </summary>
|
||||
public class RequestManager : IRequestManager
|
||||
{
|
||||
private readonly MyServiceContext _context;
|
||||
private readonly FnbEngineContext _context;
|
||||
|
||||
public RequestManager(MyServiceContext context)
|
||||
public RequestManager(FnbEngineContext context)
|
||||
{
|
||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using MyService.Domain.SeedWork;
|
||||
using MyService.Infrastructure.EntityConfigurations;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.SeedWork;
|
||||
using FnbEngine.Infrastructure.EntityConfigurations;
|
||||
|
||||
namespace MyService.Infrastructure;
|
||||
namespace FnbEngine.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// EN: EF Core DbContext for MyService.
|
||||
/// VI: EF Core DbContext cho MyService.
|
||||
/// EN: EF Core DbContext for FnbEngine.
|
||||
/// VI: EF Core DbContext cho FnbEngine.
|
||||
/// </summary>
|
||||
public class MyServiceContext : DbContext, IUnitOfWork
|
||||
public class FnbEngineContext : DbContext, IUnitOfWork
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
private IDbContextTransaction? _currentTransaction;
|
||||
@@ -34,16 +34,16 @@ public class MyServiceContext : DbContext, IUnitOfWork
|
||||
/// </summary>
|
||||
public bool HasActiveTransaction => _currentTransaction != null;
|
||||
|
||||
public MyServiceContext(DbContextOptions<MyServiceContext> options) : base(options)
|
||||
public FnbEngineContext(DbContextOptions<FnbEngineContext> options) : base(options)
|
||||
{
|
||||
_mediator = null!;
|
||||
}
|
||||
|
||||
public MyServiceContext(DbContextOptions<MyServiceContext> options, IMediator mediator) : base(options)
|
||||
public FnbEngineContext(DbContextOptions<FnbEngineContext> options, IMediator mediator) : base(options)
|
||||
{
|
||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||
|
||||
System.Diagnostics.Debug.WriteLine("MyServiceContext::ctor - " + GetHashCode());
|
||||
System.Diagnostics.Debug.WriteLine("FnbEngineContext::ctor - " + GetHashCode());
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using MyService.Domain.SeedWork;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.SeedWork;
|
||||
|
||||
namespace MyService.Infrastructure.Repositories;
|
||||
namespace FnbEngine.Infrastructure.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Repository implementation for Sample aggregate.
|
||||
@@ -10,7 +10,7 @@ namespace MyService.Infrastructure.Repositories;
|
||||
/// </summary>
|
||||
public class SampleRepository : ISampleRepository
|
||||
{
|
||||
private readonly MyServiceContext _context;
|
||||
private readonly FnbEngineContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Unit of work for transaction management.
|
||||
@@ -18,7 +18,7 @@ public class SampleRepository : ISampleRepository
|
||||
/// </summary>
|
||||
public IUnitOfWork UnitOfWork => _context;
|
||||
|
||||
public SampleRepository(MyServiceContext context)
|
||||
public SampleRepository(FnbEngineContext context)
|
||||
{
|
||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace MyService.FunctionalTests.Controllers;
|
||||
namespace FnbEngine.FunctionalTests.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Functional tests for Samples API endpoints.
|
||||
|
||||
@@ -2,9 +2,9 @@ using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MyService.Infrastructure;
|
||||
using FnbEngine.Infrastructure;
|
||||
|
||||
namespace MyService.FunctionalTests;
|
||||
namespace FnbEngine.FunctionalTests;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Custom WebApplicationFactory for functional tests.
|
||||
@@ -21,7 +21,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory<Program>
|
||||
// EN: Remove the existing DbContext registration
|
||||
// VI: Xóa đăng ký DbContext hiện tại
|
||||
var descriptor = services.SingleOrDefault(
|
||||
d => d.ServiceType == typeof(DbContextOptions<MyServiceContext>));
|
||||
d => d.ServiceType == typeof(DbContextOptions<FnbEngineContext>));
|
||||
|
||||
if (descriptor != null)
|
||||
{
|
||||
@@ -31,7 +31,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory<Program>
|
||||
// EN: Remove DbContext service
|
||||
// VI: Xóa DbContext service
|
||||
var dbContextDescriptor = services.SingleOrDefault(
|
||||
d => d.ServiceType == typeof(MyServiceContext));
|
||||
d => d.ServiceType == typeof(FnbEngineContext));
|
||||
|
||||
if (dbContextDescriptor != null)
|
||||
{
|
||||
@@ -40,7 +40,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory<Program>
|
||||
|
||||
// EN: Add in-memory database for testing
|
||||
// VI: Thêm in-memory database để test
|
||||
services.AddDbContext<MyServiceContext>(options =>
|
||||
services.AddDbContext<FnbEngineContext>(options =>
|
||||
{
|
||||
options.UseInMemoryDatabase("TestDatabase_" + Guid.NewGuid().ToString());
|
||||
});
|
||||
@@ -49,7 +49,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory<Program>
|
||||
// VI: Đảm bảo database được tạo với seed data
|
||||
var sp = services.BuildServiceProvider();
|
||||
using var scope = sp.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<MyServiceContext>();
|
||||
var db = scope.ServiceProvider.GetRequiredService<FnbEngineContext>();
|
||||
db.Database.EnsureCreated();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>MyService.FunctionalTests</AssemblyName>
|
||||
<RootNamespace>MyService.FunctionalTests</RootNamespace>
|
||||
<AssemblyName>FnbEngine.FunctionalTests</AssemblyName>
|
||||
<RootNamespace>FnbEngine.FunctionalTests</RootNamespace>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
@@ -32,7 +32,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\MyService.API\MyService.API.csproj" />
|
||||
<ProjectReference Include="..\..\src\FnbEngine.API\FnbEngine.API.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,12 +1,12 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using MyService.API.Application.Commands;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using MyService.Domain.SeedWork;
|
||||
using FnbEngine.API.Application.Commands;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.SeedWork;
|
||||
using Xunit;
|
||||
|
||||
namespace MyService.UnitTests.Application;
|
||||
namespace FnbEngine.UnitTests.Application;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Unit tests for CreateSampleCommandHandler.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using FluentAssertions;
|
||||
using MyService.Domain.AggregatesModel.SampleAggregate;
|
||||
using MyService.Domain.Exceptions;
|
||||
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
|
||||
using FnbEngine.Domain.Exceptions;
|
||||
using Xunit;
|
||||
|
||||
namespace MyService.UnitTests.Domain;
|
||||
namespace FnbEngine.UnitTests.Domain;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Unit tests for Sample aggregate.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>MyService.UnitTests</AssemblyName>
|
||||
<RootNamespace>MyService.UnitTests</RootNamespace>
|
||||
<AssemblyName>FnbEngine.UnitTests</AssemblyName>
|
||||
<RootNamespace>FnbEngine.UnitTests</RootNamespace>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
@@ -28,8 +28,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\MyService.Domain\MyService.Domain.csproj" />
|
||||
<ProjectReference Include="..\..\src\MyService.API\MyService.API.csproj" />
|
||||
<ProjectReference Include="..\..\src\FnbEngine.Domain\FnbEngine.Domain.csproj" />
|
||||
<ProjectReference Include="..\..\src\FnbEngine.API\FnbEngine.API.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user