From 28f28c4799842a609cf46d361a3d0b006b4a688a Mon Sep 17 00:00:00 2001
From: "hualin.zhu" <neo.js.cn@gmail.com>
Date: Thu, 10 Aug 2023 20:48:28 +0800
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8Refactoring=20Specification=20Query?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../AuditTrailsWithPaginationQuery.cs         | 38 ++----------
 .../Specification/AuditTrailAdvancedFilter.cs | 17 +++++
 .../AuditTrailAdvancedSpecification.cs        | 23 +++++++
 .../Commands/Create/CreateCustomerCommand.cs  |  1 +
 .../Commands/Update/UpdateCustomerCommand.cs  |  1 +
 .../Features/Customers/DTOs/CustomerDto.cs    |  1 +
 .../Queries/Export/ExportCustomersQuery.cs    |  6 +-
 .../Queries/GetAll/GetAllCustomersQuery.cs    | 60 +++++++++---------
 .../Queries/GetById/GetCustomerByIdQuery.cs   | 62 +++++++++----------
 .../Pagination/CustomersPaginationQuery.cs    | 45 ++------------
 .../Specification/CustomerAdvancedFilter.cs   | 19 ++++++
 .../Specification/CustomerAdvancedSpec.cs     | 23 +++++++
 .../Queries/Specification/CustomerByIdSpec.cs |  9 +++
 .../DocumentsWithPaginationQuery.cs           | 27 ++------
 .../Specification/AdvancedDocumentsFilter.cs  | 13 ++++
 .../AdvancedDocumentsSpecification.cs         | 16 +++++
 .../KeyValuesWithPaginationQuery.cs           | 17 ++---
 .../Specification/KeyValueAdvancedFilter.cs   |  7 +++
 .../KeyValueAdvancedSpecification.cs          | 11 ++++
 .../LogsWithPaginationQuery.cs                | 34 ++--------
 .../Specification/LoggerAdvancedFilter.cs     | 14 +++++
 .../LoggerAdvancedSpecification.cs            | 22 +++++++
 .../Queries/Export/ExportProductsQuery.cs     | 16 +----
 .../Pagination/ProductsPaginationQuery.cs     | 13 +---
 .../ExportProductSpecification.cs             | 29 ---------
 .../Specification/ProductAdvancedFilter.cs    | 12 ++++
 .../ProductAdvancedSpecification.cs           | 30 +++++++++
 .../SearchProductSpecification.cs             | 31 ----------
 .../Pages/Customers/Customers.razor           |  1 +
 .../Pages/Documents/Documents.razor           |  1 +
 .../Pages/SystemManagement/AuditTrails.razor  |  1 +
 .../Pages/SystemManagement/Logs.razor         |  1 +
 32 files changed, 313 insertions(+), 288 deletions(-)
 create mode 100644 src/Application/Features/AuditTrails/Queries/Specification/AuditTrailAdvancedFilter.cs
 create mode 100644 src/Application/Features/AuditTrails/Queries/Specification/AuditTrailAdvancedSpecification.cs
 create mode 100644 src/Application/Features/Customers/Queries/Specification/CustomerAdvancedFilter.cs
 create mode 100644 src/Application/Features/Customers/Queries/Specification/CustomerAdvancedSpec.cs
 create mode 100644 src/Application/Features/Customers/Queries/Specification/CustomerByIdSpec.cs
 create mode 100644 src/Application/Features/Documents/Queries/Specification/AdvancedDocumentsFilter.cs
 create mode 100644 src/Application/Features/Documents/Queries/Specification/AdvancedDocumentsSpecification.cs
 create mode 100644 src/Application/Features/KeyValues/Queries/Specification/KeyValueAdvancedFilter.cs
 create mode 100644 src/Application/Features/KeyValues/Queries/Specification/KeyValueAdvancedSpecification.cs
 create mode 100644 src/Application/Features/Loggers/Queries/Specification/LoggerAdvancedFilter.cs
 create mode 100644 src/Application/Features/Loggers/Queries/Specification/LoggerAdvancedSpecification.cs
 delete mode 100644 src/Application/Features/Products/Queries/Specification/ExportProductSpecification.cs
 create mode 100644 src/Application/Features/Products/Queries/Specification/ProductAdvancedFilter.cs
 create mode 100644 src/Application/Features/Products/Queries/Specification/ProductAdvancedSpecification.cs
 delete mode 100644 src/Application/Features/Products/Queries/Specification/SearchProductSpecification.cs

diff --git a/src/Application/Features/AuditTrails/Queries/PaginationQuery/AuditTrailsWithPaginationQuery.cs b/src/Application/Features/AuditTrails/Queries/PaginationQuery/AuditTrailsWithPaginationQuery.cs
index 45f9f0548..3356c0a46 100644
--- a/src/Application/Features/AuditTrails/Queries/PaginationQuery/AuditTrailsWithPaginationQuery.cs
+++ b/src/Application/Features/AuditTrails/Queries/PaginationQuery/AuditTrailsWithPaginationQuery.cs
@@ -3,18 +3,16 @@
 
 using CleanArchitecture.Blazor.Application.Features.AuditTrails.Caching;
 using CleanArchitecture.Blazor.Application.Features.AuditTrails.DTOs;
-using CleanArchitecture.Blazor.Domain.Enums;
+using CleanArchitecture.Blazor.Application.Features.AuditTrails.Queries.Specification;
 
 namespace CleanArchitecture.Blazor.Application.Features.AuditTrails.Queries.PaginationQuery;
 
-public class AuditTrailsWithPaginationQuery : PaginationFilter, ICacheableRequest<PaginatedData<AuditTrailDto>>
+public class AuditTrailsWithPaginationQuery : AuditTrailAdvancedFilter, ICacheableRequest<PaginatedData<AuditTrailDto>>
 {
-    public AuditType? AuditType { get; set; }
-    public AuditTrailListView ListView { get; set; } = AuditTrailListView.All;
+   
     public string CacheKey => AuditTrailsCacheKey.GetPaginationCacheKey($"{this}");
-    public UserProfile? CurrentUser { get; set; }
     public MemoryCacheEntryOptions? Options => AuditTrailsCacheKey.MemoryCacheEntryOptions;
-    public AuditTrailsQuerySpec Specification => new AuditTrailsQuerySpec(this);
+    public AuditTrailAdvancedSpecification Specification => new AuditTrailAdvancedSpecification(this);
     public override string ToString()
     {
         return
@@ -49,32 +47,4 @@ public async Task<PaginatedData<AuditTrailDto>> Handle(AuditTrailsWithPagination
     }
 }
 
-public enum AuditTrailListView
-{
-    [Description("All")] All,
-    [Description("My Change Histories")] My,
-    [Description("Created Toady")] CreatedToday,
-    [Description("View of the last 30 days")]
-    Last30days
-}
-public class AuditTrailsQuerySpec : Specification<AuditTrail>
-{
-    public AuditTrailsQuerySpec(AuditTrailsWithPaginationQuery request)
-    {
-        var today = DateTime.Now.Date;
-        var start = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
-            CultureInfo.CurrentCulture);
-        var end = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 23:59:59",
-            CultureInfo.CurrentCulture);
-        var last30day = Convert.ToDateTime(
-            today.AddDays(-30).ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
-            CultureInfo.CurrentCulture);
-
-        Query.Where(p => p.AuditType==request.AuditType, request.AuditType is not null) 
-             .Where(p => p.UserId == request.CurrentUser.UserId, request.ListView == AuditTrailListView.My && request.CurrentUser is not null)
-             .Where(p => p.DateTime.Date == DateTime.Now.Date, request.ListView == AuditTrailListView.CreatedToday)
-             .Where(p => p.DateTime >= last30day, request.ListView == AuditTrailListView.Last30days)
-             .Where(x => x.TableName.Contains(request.Keyword) , !string.IsNullOrEmpty(request.Keyword));
 
-    }
-}
\ No newline at end of file
diff --git a/src/Application/Features/AuditTrails/Queries/Specification/AuditTrailAdvancedFilter.cs b/src/Application/Features/AuditTrails/Queries/Specification/AuditTrailAdvancedFilter.cs
new file mode 100644
index 000000000..4953f652b
--- /dev/null
+++ b/src/Application/Features/AuditTrails/Queries/Specification/AuditTrailAdvancedFilter.cs
@@ -0,0 +1,17 @@
+using CleanArchitecture.Blazor.Domain.Enums;
+
+namespace CleanArchitecture.Blazor.Application.Features.AuditTrails.Queries.Specification;
+public enum AuditTrailListView
+{
+    [Description("All")] All,
+    [Description("My Change Histories")] My,
+    [Description("Created Toady")] CreatedToday,
+    [Description("View of the last 30 days")]
+    Last30days
+}
+public class AuditTrailAdvancedFilter : PaginationFilter
+{
+    public AuditType? AuditType { get; set; }
+    public AuditTrailListView ListView { get; set; } = AuditTrailListView.All;
+    public UserProfile? CurrentUser { get; set; }
+}
diff --git a/src/Application/Features/AuditTrails/Queries/Specification/AuditTrailAdvancedSpecification.cs b/src/Application/Features/AuditTrails/Queries/Specification/AuditTrailAdvancedSpecification.cs
new file mode 100644
index 000000000..2108106d0
--- /dev/null
+++ b/src/Application/Features/AuditTrails/Queries/Specification/AuditTrailAdvancedSpecification.cs
@@ -0,0 +1,23 @@
+namespace CleanArchitecture.Blazor.Application.Features.AuditTrails.Queries.Specification;
+
+public class AuditTrailAdvancedSpecification : Specification<AuditTrail>
+{
+    public AuditTrailAdvancedSpecification(AuditTrailAdvancedFilter filter)
+    {
+        var today = DateTime.Now.Date;
+        var start = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
+            CultureInfo.CurrentCulture);
+        var end = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 23:59:59",
+            CultureInfo.CurrentCulture);
+        var last30day = Convert.ToDateTime(
+            today.AddDays(-30).ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
+            CultureInfo.CurrentCulture);
+
+        Query.Where(p => p.AuditType == filter.AuditType, filter.AuditType is not null)
+             .Where(p => p.UserId == filter.CurrentUser.UserId, filter.ListView == AuditTrailListView.My && filter.CurrentUser is not null)
+             .Where(p => p.DateTime.Date == DateTime.Now.Date, filter.ListView == AuditTrailListView.CreatedToday)
+             .Where(p => p.DateTime >= last30day, filter.ListView == AuditTrailListView.Last30days)
+             .Where(x => x.TableName.Contains(filter.Keyword), !string.IsNullOrEmpty(filter.Keyword));
+
+    }
+}
\ No newline at end of file
diff --git a/src/Application/Features/Customers/Commands/Create/CreateCustomerCommand.cs b/src/Application/Features/Customers/Commands/Create/CreateCustomerCommand.cs
index 79c7dddb9..17f61a1ee 100644
--- a/src/Application/Features/Customers/Commands/Create/CreateCustomerCommand.cs
+++ b/src/Application/Features/Customers/Commands/Create/CreateCustomerCommand.cs
@@ -1,5 +1,6 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
+using System.ComponentModel;
 using CleanArchitecture.Blazor.Application.Features.Customers.DTOs;
 using CleanArchitecture.Blazor.Application.Features.Customers.Caching;
 
diff --git a/src/Application/Features/Customers/Commands/Update/UpdateCustomerCommand.cs b/src/Application/Features/Customers/Commands/Update/UpdateCustomerCommand.cs
index 2fd391010..eafb6dc24 100644
--- a/src/Application/Features/Customers/Commands/Update/UpdateCustomerCommand.cs
+++ b/src/Application/Features/Customers/Commands/Update/UpdateCustomerCommand.cs
@@ -1,5 +1,6 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
+using System.ComponentModel;
 using CleanArchitecture.Blazor.Application.Features.Customers.DTOs;
 using CleanArchitecture.Blazor.Application.Features.Customers.Caching;
 
diff --git a/src/Application/Features/Customers/DTOs/CustomerDto.cs b/src/Application/Features/Customers/DTOs/CustomerDto.cs
index 3e2b86e81..15785e31c 100644
--- a/src/Application/Features/Customers/DTOs/CustomerDto.cs
+++ b/src/Application/Features/Customers/DTOs/CustomerDto.cs
@@ -1,6 +1,7 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System.ComponentModel;
 namespace CleanArchitecture.Blazor.Application.Features.Customers.DTOs;
 
 [Description("Customers")]
diff --git a/src/Application/Features/Customers/Queries/Export/ExportCustomersQuery.cs b/src/Application/Features/Customers/Queries/Export/ExportCustomersQuery.cs
index 575b636be..a9d36a098 100644
--- a/src/Application/Features/Customers/Queries/Export/ExportCustomersQuery.cs
+++ b/src/Application/Features/Customers/Queries/Export/ExportCustomersQuery.cs
@@ -1,19 +1,19 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-
 using CleanArchitecture.Blazor.Application.Features.Customers.DTOs;
 using CleanArchitecture.Blazor.Application.Features.Customers.Queries.Pagination;
+using CleanArchitecture.Blazor.Application.Features.Customers.Queries.Specification;
 
 namespace CleanArchitecture.Blazor.Application.Features.Customers.Queries.Export;
 
-public class ExportCustomersQuery : BaseFilter, IRequest<Result<byte[]>>
+public class ExportCustomersQuery : CustomerAdvancedFilter, IRequest<Result<byte[]>>
 {
       public string OrderBy { get; set; } = "Id";
       public string SortDirection { get; set; } = "Descending";
       public CustomerListView ListView { get; set; } = CustomerListView.All;
       public UserProfile? CurrentUser { get; set; }
-      public CustomersExportSpecification Specification => new CustomersExportSpecification(this);
+      public CustomerAdvancedPaginationSpec Specification => new CustomerAdvancedPaginationSpec(this);
 }
     
 public class ExportCustomersQueryHandler :
diff --git a/src/Application/Features/Customers/Queries/GetAll/GetAllCustomersQuery.cs b/src/Application/Features/Customers/Queries/GetAll/GetAllCustomersQuery.cs
index 4fa5d6465..f3fb34a0b 100644
--- a/src/Application/Features/Customers/Queries/GetAll/GetAllCustomersQuery.cs
+++ b/src/Application/Features/Customers/Queries/GetAll/GetAllCustomersQuery.cs
@@ -6,39 +6,39 @@
 
 namespace CleanArchitecture.Blazor.Application.Features.Customers.Queries.GetAll;
 
-    public class GetAllCustomersQuery : ICacheableRequest<IEnumerable<CustomerDto>>
+public class GetAllCustomersQuery : ICacheableRequest<IEnumerable<CustomerDto>>
+{
+   public string CacheKey => CustomerCacheKey.GetAllCacheKey;
+   public MemoryCacheEntryOptions? Options => CustomerCacheKey.MemoryCacheEntryOptions;
+}
+
+public class GetAllCustomersQueryHandler :
+     IRequestHandler<GetAllCustomersQuery, IEnumerable<CustomerDto>>
+{
+    private readonly IApplicationDbContext _context;
+    private readonly IMapper _mapper;
+    private readonly IStringLocalizer<GetAllCustomersQueryHandler> _localizer;
+
+    public GetAllCustomersQueryHandler(
+        IApplicationDbContext context,
+        IMapper mapper,
+        IStringLocalizer<GetAllCustomersQueryHandler> localizer
+        )
     {
-       public string CacheKey => CustomerCacheKey.GetAllCacheKey;
-       public MemoryCacheEntryOptions? Options => CustomerCacheKey.MemoryCacheEntryOptions;
+        _context = context;
+        _mapper = mapper;
+        _localizer = localizer;
     }
-    
-    public class GetAllCustomersQueryHandler :
-         IRequestHandler<GetAllCustomersQuery, IEnumerable<CustomerDto>>
+
+    public async Task<IEnumerable<CustomerDto>> Handle(GetAllCustomersQuery request, CancellationToken cancellationToken)
     {
-        private readonly IApplicationDbContext _context;
-        private readonly IMapper _mapper;
-        private readonly IStringLocalizer<GetAllCustomersQueryHandler> _localizer;
-
-        public GetAllCustomersQueryHandler(
-            IApplicationDbContext context,
-            IMapper mapper,
-            IStringLocalizer<GetAllCustomersQueryHandler> localizer
-            )
-        {
-            _context = context;
-            _mapper = mapper;
-            _localizer = localizer;
-        }
-
-        public async Task<IEnumerable<CustomerDto>> Handle(GetAllCustomersQuery request, CancellationToken cancellationToken)
-        {
-            // TODO: Implement GetAllCustomersQueryHandler method 
-            var data = await _context.Customers
-                         .ProjectTo<CustomerDto>(_mapper.ConfigurationProvider)
-                         .AsNoTracking()
-                         .ToListAsync(cancellationToken);
-            return data;
-        }
+        // TODO: Implement GetAllCustomersQueryHandler method 
+        var data = await _context.Customers
+                     .ProjectTo<CustomerDto>(_mapper.ConfigurationProvider)
+                     .AsNoTracking()
+                     .ToListAsync(cancellationToken);
+        return data;
     }
+}
 
 
diff --git a/src/Application/Features/Customers/Queries/GetById/GetCustomerByIdQuery.cs b/src/Application/Features/Customers/Queries/GetById/GetCustomerByIdQuery.cs
index 53484ee7a..0805b328d 100644
--- a/src/Application/Features/Customers/Queries/GetById/GetCustomerByIdQuery.cs
+++ b/src/Application/Features/Customers/Queries/GetById/GetCustomerByIdQuery.cs
@@ -6,39 +6,37 @@
 
 namespace CleanArchitecture.Blazor.Application.Features.Customers.Queries.GetById;
 
-    public class GetCustomerByIdQuery : ICacheableRequest<CustomerDto>
-    {
-       public required int Id { get; set; }
-       public string CacheKey => CustomerCacheKey.GetByIdCacheKey($"{Id}");
-       public MemoryCacheEntryOptions? Options => CustomerCacheKey.MemoryCacheEntryOptions;
-    }
-    
-    public class GetCustomerByIdQueryHandler :
-         IRequestHandler<GetCustomerByIdQuery, CustomerDto>
-    {
-        private readonly IApplicationDbContext _context;
-        private readonly IMapper _mapper;
-        private readonly IStringLocalizer<GetCustomerByIdQueryHandler> _localizer;
+public class GetCustomerByIdQuery : ICacheableRequest<CustomerDto>
+{
+   public required int Id { get; set; }
+   public string CacheKey => CustomerCacheKey.GetByIdCacheKey($"{Id}");
+   public MemoryCacheEntryOptions? Options => CustomerCacheKey.MemoryCacheEntryOptions;
+}
 
-        public GetCustomerByIdQueryHandler(
-            IApplicationDbContext context,
-            IMapper mapper,
-            IStringLocalizer<GetCustomerByIdQueryHandler> localizer
-            )
-        {
-            _context = context;
-            _mapper = mapper;
-            _localizer = localizer;
-        }
+public class GetCustomerByIdQueryHandler :
+     IRequestHandler<GetCustomerByIdQuery, CustomerDto>
+{
+    private readonly IApplicationDbContext _context;
+    private readonly IMapper _mapper;
+    private readonly IStringLocalizer<GetCustomerByIdQueryHandler> _localizer;
 
-        public async Task<CustomerDto> Handle(GetCustomerByIdQuery request, CancellationToken cancellationToken)
-        {
-            // TODO: Implement GetCustomerByIdQueryHandler method 
-            var data = await _context.Customers.Where(x => x.Id == request.Id)
-                         .ProjectTo<CustomerDto>(_mapper.ConfigurationProvider)
-                         .FirstAsync(cancellationToken) ?? throw new NotFoundException($"Customer with id: [{request.Id}] not found.");;
-            return data;
-        }
+    public GetCustomerByIdQueryHandler(
+        IApplicationDbContext context,
+        IMapper mapper,
+        IStringLocalizer<GetCustomerByIdQueryHandler> localizer
+        )
+    {
+        _context = context;
+        _mapper = mapper;
+        _localizer = localizer;
     }
 
-
+    public async Task<CustomerDto> Handle(GetCustomerByIdQuery request, CancellationToken cancellationToken)
+    {
+        // TODO: Implement GetCustomerByIdQueryHandler method 
+        var data = await _context.Customers.ApplySpecification(new CustomerByIdSpec(request.Id))
+                     .ProjectTo<CustomerDto>(_mapper.ConfigurationProvider)
+                     .FirstAsync(cancellationToken) ?? throw new NotFoundException($"Customer with id: [{request.Id}] not found.");;
+        return data;
+    }
+}
diff --git a/src/Application/Features/Customers/Queries/Pagination/CustomersPaginationQuery.cs b/src/Application/Features/Customers/Queries/Pagination/CustomersPaginationQuery.cs
index 385771e34..c327c3f3d 100644
--- a/src/Application/Features/Customers/Queries/Pagination/CustomersPaginationQuery.cs
+++ b/src/Application/Features/Customers/Queries/Pagination/CustomersPaginationQuery.cs
@@ -3,20 +3,19 @@
 
 using CleanArchitecture.Blazor.Application.Features.Customers.DTOs;
 using CleanArchitecture.Blazor.Application.Features.Customers.Caching;
+using CleanArchitecture.Blazor.Application.Features.Customers.Queries.Specification;
 
 namespace CleanArchitecture.Blazor.Application.Features.Customers.Queries.Pagination;
 
-public class CustomersWithPaginationQuery : PaginationFilter, ICacheableRequest<PaginatedData<CustomerDto>>
+public class CustomersWithPaginationQuery : CustomerAdvancedFilter, ICacheableRequest<PaginatedData<CustomerDto>>
 {
-    public CustomerListView ListView { get; set; } = CustomerListView.All; 
-    public UserProfile? CurrentUser { get; set; }
     public override string ToString()
     {
         return $"Listview:{ListView}, Search:{Keyword}, {OrderBy}, {SortDirection}, {PageNumber}, {PageSize}";
     }
     public string CacheKey => CustomerCacheKey.GetPaginationCacheKey($"{this}");
     public MemoryCacheEntryOptions? Options => CustomerCacheKey.MemoryCacheEntryOptions;
-    public CustomersPaginationSpecification Specification => new CustomersPaginationSpecification(this);
+    public CustomerAdvancedPaginationSpec Specification => new CustomerAdvancedPaginationSpec(this);
 }
     
 public class CustomersWithPaginationQueryHandler :
@@ -41,41 +40,7 @@ public async Task<PaginatedData<CustomerDto>> Handle(CustomersWithPaginationQuer
         {
            // TODO: Implement CustomersWithPaginationQueryHandler method 
            var data = await _context.Customers.OrderBy($"{request.OrderBy} {request.SortDirection}")
-                        .ProjectToPaginatedDataAsync<Customer, CustomerDto>(request.Specification, request.PageNumber, request.PageSize, _mapper.ConfigurationProvider, cancellationToken);
-        return data;
+                                    .ProjectToPaginatedDataAsync<Customer, CustomerDto>(request.Specification, request.PageNumber, request.PageSize, _mapper.ConfigurationProvider, cancellationToken);
+            return data;
         }
-}
-
-public class CustomersPaginationSpecification : Specification<Customer>
-{
-    public CustomersPaginationSpecification(CustomersWithPaginationQuery query)
-    {
-        var today = DateTime.Now.Date;
-        var start = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
-            CultureInfo.CurrentCulture);
-        var end = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 23:59:59",
-            CultureInfo.CurrentCulture);
-        var last30day = Convert.ToDateTime(
-            today.AddDays(-30).ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
-            CultureInfo.CurrentCulture);
-
-       Query.Where(q => q.Name != null)
-             .Where(q => q.Name!.Contains(query.Keyword) || q.Description!.Contains(query.Keyword), !string.IsNullOrEmpty(query.Keyword))
-             .Where(q => q.CreatedBy == query.CurrentUser.UserId, query.ListView == CustomerListView.My && query.CurrentUser is not null)
-             .Where(q => q.Created >= start && q.Created <= end, query.ListView == CustomerListView.CreatedToday)
-             .Where(q => q.Created >= last30day, query.ListView == CustomerListView.Created30Days);
-       
-    }
-}
-
-public enum CustomerListView
-{
-    [Description("All")]
-    All,
-    [Description("My")]
-    My,
-    [Description("Created Toady")]
-    CreatedToday,
-    [Description("Created within the last 30 days")]
-    Created30Days
 }
\ No newline at end of file
diff --git a/src/Application/Features/Customers/Queries/Specification/CustomerAdvancedFilter.cs b/src/Application/Features/Customers/Queries/Specification/CustomerAdvancedFilter.cs
new file mode 100644
index 000000000..47936fbd9
--- /dev/null
+++ b/src/Application/Features/Customers/Queries/Specification/CustomerAdvancedFilter.cs
@@ -0,0 +1,19 @@
+namespace CleanArchitecture.Blazor.Application.Features.Customers.Queries.Specification;
+
+public enum CustomerListView
+{
+    [Description("All")]
+    All,
+    [Description("My")]
+    My,
+    [Description("Created Toady")]
+    CreatedToday,
+    [Description("Created within the last 30 days")]
+    Created30Days
+}
+
+public class CustomerAdvancedFilter: PaginationFilter
+{
+    public CustomerListView ListView { get; set; } = CustomerListView.All;
+    public UserProfile? CurrentUser { get; set; }
+}
\ No newline at end of file
diff --git a/src/Application/Features/Customers/Queries/Specification/CustomerAdvancedSpec.cs b/src/Application/Features/Customers/Queries/Specification/CustomerAdvancedSpec.cs
new file mode 100644
index 000000000..7ece24ff8
--- /dev/null
+++ b/src/Application/Features/Customers/Queries/Specification/CustomerAdvancedSpec.cs
@@ -0,0 +1,23 @@
+namespace CleanArchitecture.Blazor.Application.Features.Customers.Queries.Specification;
+
+public class CustomerAdvancedPaginationSpec : Specification<Customer>
+{
+    public CustomerAdvancedPaginationSpec(CustomerAdvancedFilter filter)
+    {
+        var today = DateTime.Now.Date;
+        var start = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
+            CultureInfo.CurrentCulture);
+        var end = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 23:59:59",
+            CultureInfo.CurrentCulture);
+        var last30day = Convert.ToDateTime(
+            today.AddDays(-30).ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
+            CultureInfo.CurrentCulture);
+
+       Query.Where(q => q.Name != null)
+             .Where(q => q.Name!.Contains(filter.Keyword) || q.Description!.Contains(filter.Keyword), !string.IsNullOrEmpty(filter.Keyword))
+             .Where(q => q.CreatedBy == filter.CurrentUser.UserId, filter.ListView == CustomerListView.My && filter.CurrentUser is not null)
+             .Where(q => q.Created >= start && q.Created <= end, filter.ListView == CustomerListView.CreatedToday)
+             .Where(q => q.Created >= last30day, filter.ListView == CustomerListView.Created30Days);
+       
+    }
+}
\ No newline at end of file
diff --git a/src/Application/Features/Customers/Queries/Specification/CustomerByIdSpec.cs b/src/Application/Features/Customers/Queries/Specification/CustomerByIdSpec.cs
new file mode 100644
index 000000000..61be0bd9a
--- /dev/null
+++ b/src/Application/Features/Customers/Queries/Specification/CustomerByIdSpec.cs
@@ -0,0 +1,9 @@
+namespace CleanArchitecture.Blazor.Application.Features.Customers.Queries.Specification;
+
+public class CustomerByIdSpec : Specification<Customer>
+{
+    public CustomerByIdSpec(int id)
+    {
+       Query.Where(q => q.Id == id);
+    }
+}
\ No newline at end of file
diff --git a/src/Application/Features/Documents/Queries/PaginationQuery/DocumentsWithPaginationQuery.cs b/src/Application/Features/Documents/Queries/PaginationQuery/DocumentsWithPaginationQuery.cs
index cc1f25c4d..9276d9762 100644
--- a/src/Application/Features/Documents/Queries/PaginationQuery/DocumentsWithPaginationQuery.cs
+++ b/src/Application/Features/Documents/Queries/PaginationQuery/DocumentsWithPaginationQuery.cs
@@ -3,13 +3,13 @@
 
 using CleanArchitecture.Blazor.Application.Features.Documents.Caching;
 using CleanArchitecture.Blazor.Application.Features.Documents.DTOs;
+using CleanArchitecture.Blazor.Application.Features.Documents.Queries.Specification;
 
 namespace CleanArchitecture.Blazor.Application.Features.Documents.Queries.PaginationQuery;
 
-public class DocumentsWithPaginationQuery : PaginationFilter, ICacheableRequest<PaginatedData<DocumentDto>>
+public class DocumentsWithPaginationQuery : AdvancedDocumentsFilter, ICacheableRequest<PaginatedData<DocumentDto>>
 {
-    public DocumentListView ListView { get; set; } = DocumentListView.All;
-    public required UserProfile CurrentUser { get; set; }
+    
     public string CacheKey => DocumentCacheKey.GetPaginationCacheKey($"{this}");
     public MemoryCacheEntryOptions? Options => DocumentCacheKey.MemoryCacheEntryOptions;
 
@@ -19,7 +19,7 @@ public override string ToString()
             $"CurrentUserId:{CurrentUser?.UserId},ListView:{ListView},Search:{Keyword},OrderBy:{OrderBy} {SortDirection},{PageNumber},{PageSize}";
     }
 
-    public DocumentsQuerySpec Specification=>new DocumentsQuerySpec(this);
+    public AdvancedDocumentsSpecification Specification =>new AdvancedDocumentsSpecification(this);
 }
 
 public class DocumentsQueryHandler : IRequestHandler<DocumentsWithPaginationQuery, PaginatedData<DocumentDto>>
@@ -47,24 +47,5 @@ public async Task<PaginatedData<DocumentDto>> Handle(DocumentsWithPaginationQuer
 
     
 }
-public class DocumentsQuerySpec : Specification<Document>
-{
-    public DocumentsQuerySpec(DocumentsWithPaginationQuery request)
-    {
-        Query.Where(p =>
-                (p.CreatedBy == request.CurrentUser.UserId && p.IsPublic == false) ||
-                (p.IsPublic == true && p.TenantId == request.CurrentUser.TenantId), request.ListView == DocumentListView.All)
-             .Where(p =>
-                p.CreatedBy == request.CurrentUser.UserId && p.TenantId == request.CurrentUser.TenantId, request.ListView == DocumentListView.My)
-             .Where(p => p.Created.Value.Date == DateTime.Now.Date, request.ListView == DocumentListView.CreatedToday)
-             .Where(x => x.Title.Contains(request.Keyword) || x.Description.Contains(request.Keyword) || x.Content.Contains(request.Keyword), !string.IsNullOrEmpty(request.Keyword));
 
-        }
-}
 
-public enum DocumentListView
-{
-    [Description("All")] All,
-    [Description("My Document")] My,
-    [Description("Created Toady")] CreatedToday
-}
\ No newline at end of file
diff --git a/src/Application/Features/Documents/Queries/Specification/AdvancedDocumentsFilter.cs b/src/Application/Features/Documents/Queries/Specification/AdvancedDocumentsFilter.cs
new file mode 100644
index 000000000..b3eaf9318
--- /dev/null
+++ b/src/Application/Features/Documents/Queries/Specification/AdvancedDocumentsFilter.cs
@@ -0,0 +1,13 @@
+namespace CleanArchitecture.Blazor.Application.Features.Documents.Queries.Specification;
+
+public enum DocumentListView
+{
+    [Description("All")] All,
+    [Description("My Document")] My,
+    [Description("Created Toady")] CreatedToday
+}
+public class AdvancedDocumentsFilter: PaginationFilter
+{
+    public DocumentListView ListView { get; set; } = DocumentListView.All;
+    public required UserProfile CurrentUser { get; set; }
+}
diff --git a/src/Application/Features/Documents/Queries/Specification/AdvancedDocumentsSpecification.cs b/src/Application/Features/Documents/Queries/Specification/AdvancedDocumentsSpecification.cs
new file mode 100644
index 000000000..05a667259
--- /dev/null
+++ b/src/Application/Features/Documents/Queries/Specification/AdvancedDocumentsSpecification.cs
@@ -0,0 +1,16 @@
+namespace CleanArchitecture.Blazor.Application.Features.Documents.Queries.Specification;
+ 
+public class AdvancedDocumentsSpecification : Specification<Document>
+{
+    public AdvancedDocumentsSpecification(AdvancedDocumentsFilter filter)
+    {
+        Query.Where(p =>
+                (p.CreatedBy == filter.CurrentUser.UserId && p.IsPublic == false) ||
+                (p.IsPublic == true && p.TenantId == filter.CurrentUser.TenantId), filter.ListView == DocumentListView.All)
+             .Where(p =>
+                p.CreatedBy == filter.CurrentUser.UserId && p.TenantId == filter.CurrentUser.TenantId, filter.ListView == DocumentListView.My)
+             .Where(p => p.Created.Value.Date == DateTime.Now.Date, filter.ListView == DocumentListView.CreatedToday)
+             .Where(x => x.Title.Contains(filter.Keyword) || x.Description.Contains(filter.Keyword) || x.Content.Contains(filter.Keyword), !string.IsNullOrEmpty(filter.Keyword));
+
+    }
+}
diff --git a/src/Application/Features/KeyValues/Queries/PaginationQuery/KeyValuesWithPaginationQuery.cs b/src/Application/Features/KeyValues/Queries/PaginationQuery/KeyValuesWithPaginationQuery.cs
index 7dfa7f6aa..fa66c22a4 100644
--- a/src/Application/Features/KeyValues/Queries/PaginationQuery/KeyValuesWithPaginationQuery.cs
+++ b/src/Application/Features/KeyValues/Queries/PaginationQuery/KeyValuesWithPaginationQuery.cs
@@ -3,20 +3,20 @@
 
 using CleanArchitecture.Blazor.Application.Features.KeyValues.Caching;
 using CleanArchitecture.Blazor.Application.Features.KeyValues.DTOs;
-using CleanArchitecture.Blazor.Domain.Enums;
+using CleanArchitecture.Blazor.Application.Features.KeyValues.Queries.Specification;
 
 namespace CleanArchitecture.Blazor.Application.Features.KeyValues.Queries.PaginationQuery;
 
-public class KeyValuesWithPaginationQuery : PaginationFilter, ICacheableRequest<PaginatedData<KeyValueDto>>
+public class KeyValuesWithPaginationQuery : KeyValueAdvancedFilter, ICacheableRequest<PaginatedData<KeyValueDto>>
 {
-    public Picklist? Picklist { get; set; }
+  
     public string CacheKey => $"{nameof(KeyValuesWithPaginationQuery)},{this}";
     public MemoryCacheEntryOptions? Options => KeyValueCacheKey.MemoryCacheEntryOptions;
     public override string ToString()
     {
         return $"Picklist:{Picklist},Search:{Keyword},OrderBy:{OrderBy} {SortDirection},{PageNumber},{PageSize}";
     }
-    public KeyValuesQuerySpec Specification => new KeyValuesQuerySpec(this);
+    public KeyValueAdvancedSpecification Specification => new KeyValueAdvancedSpecification(this);
 }
 
 public class KeyValuesQueryHandler : IRequestHandler<KeyValuesWithPaginationQuery, PaginatedData<KeyValueDto>>
@@ -42,12 +42,3 @@ public async Task<PaginatedData<KeyValueDto>> Handle(KeyValuesWithPaginationQuer
         return data;
     }
 }
-public class KeyValuesQuerySpec : Specification<KeyValue>
-{
-    public KeyValuesQuerySpec(KeyValuesWithPaginationQuery request)
-    {
-        Query.Where(p => p.Name== request.Picklist, request.Picklist is not null)
-             .Where(x => x.Description.Contains(request.Keyword) || x.Text.Contains(request.Keyword) || x.Value.Contains(request.Keyword), !string.IsNullOrEmpty(request.Keyword));
-
-    }
-}
\ No newline at end of file
diff --git a/src/Application/Features/KeyValues/Queries/Specification/KeyValueAdvancedFilter.cs b/src/Application/Features/KeyValues/Queries/Specification/KeyValueAdvancedFilter.cs
new file mode 100644
index 000000000..1260b5aa3
--- /dev/null
+++ b/src/Application/Features/KeyValues/Queries/Specification/KeyValueAdvancedFilter.cs
@@ -0,0 +1,7 @@
+using CleanArchitecture.Blazor.Domain.Enums;
+
+namespace CleanArchitecture.Blazor.Application.Features.KeyValues.Queries.Specification;
+public class KeyValueAdvancedFilter: PaginationFilter
+{
+    public Picklist? Picklist { get; set; }
+}
diff --git a/src/Application/Features/KeyValues/Queries/Specification/KeyValueAdvancedSpecification.cs b/src/Application/Features/KeyValues/Queries/Specification/KeyValueAdvancedSpecification.cs
new file mode 100644
index 000000000..85eaf3594
--- /dev/null
+++ b/src/Application/Features/KeyValues/Queries/Specification/KeyValueAdvancedSpecification.cs
@@ -0,0 +1,11 @@
+namespace CleanArchitecture.Blazor.Application.Features.KeyValues.Queries.Specification;
+
+public class KeyValueAdvancedSpecification : Specification<KeyValue>
+{
+    public KeyValueAdvancedSpecification(KeyValueAdvancedFilter filter)
+    {
+        Query.Where(p => p.Name == filter.Picklist, filter.Picklist is not null)
+             .Where(x => x.Description.Contains(filter.Keyword) || x.Text.Contains(filter.Keyword) || x.Value.Contains(filter.Keyword), !string.IsNullOrEmpty(filter.Keyword));
+
+    }
+}
diff --git a/src/Application/Features/Loggers/Queries/PaginationQuery/LogsWithPaginationQuery.cs b/src/Application/Features/Loggers/Queries/PaginationQuery/LogsWithPaginationQuery.cs
index ad9579c06..705ea3b20 100644
--- a/src/Application/Features/Loggers/Queries/PaginationQuery/LogsWithPaginationQuery.cs
+++ b/src/Application/Features/Loggers/Queries/PaginationQuery/LogsWithPaginationQuery.cs
@@ -3,21 +3,21 @@
 
 using CleanArchitecture.Blazor.Application.Features.Loggers.Caching;
 using CleanArchitecture.Blazor.Application.Features.Loggers.DTOs;
+using CleanArchitecture.Blazor.Application.Features.Loggers.Queries.Specification;
 using CleanArchitecture.Blazor.Domain.Entities.Logger;
 
 namespace CleanArchitecture.Blazor.Application.Features.Loggers.Queries.PaginationQuery;
 
-public class LogsWithPaginationQuery : PaginationFilter, ICacheableRequest<PaginatedData<LogDto>>
+public class LogsWithPaginationQuery : LoggerAdvancedFilter, ICacheableRequest<PaginatedData<LogDto>>
 {
-    public LogLevel? Level { get; set; }
-    public LogListView ListView { get; set; } = LogListView.All;
+    
     public string CacheKey => LogsCacheKey.GetPaginationCacheKey($"{this}");
     public MemoryCacheEntryOptions? Options => LogsCacheKey.MemoryCacheEntryOptions;
     public override string ToString()
     {
         return $"Listview:{ListView},{Level},Search:{Keyword},OrderBy:{OrderBy} {SortDirection},{PageNumber},{PageSize}";
     }
-    public LogsQuerySpec Specification => new LogsQuerySpec(this);
+    public LoggerAdvancedSpecification Specification => new LoggerAdvancedSpecification(this);
 }
 
 public class LogsQueryHandler : IRequestHandler<LogsWithPaginationQuery, PaginatedData<LogDto>>
@@ -43,29 +43,5 @@ public async Task<PaginatedData<LogDto>> Handle(LogsWithPaginationQuery request,
     }
 }
 
-public class LogsQuerySpec : Specification<Logger>
-{
-    public LogsQuerySpec(LogsWithPaginationQuery request)
-    {
-        var today = DateTime.Now.Date;
-        var start = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
-            CultureInfo.CurrentCulture);
-        var end = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 23:59:59",
-            CultureInfo.CurrentCulture);
-        var last30days =
-            Convert.ToDateTime(today.AddDays(-30).ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
-                CultureInfo.CurrentCulture);
-        Query.Where(p => p.TimeStamp.Date == DateTime.Now.Date, request.ListView == LogListView.CreatedToday)
-             .Where(p => p.TimeStamp >= last30days, request.ListView == LogListView.Last30days)
-             .Where(p => p.Level== request.Level.ToString(), request.Level is not null)
-             .Where(x => x.Message.Contains(request.Keyword) || x.Exception.Contains(request.Keyword) || x.UserName.Contains(request.Keyword), !string.IsNullOrEmpty(request.Keyword));
-    }
-}
 
-public enum LogListView
-{
-    [Description("All")] All,
-    [Description("Created Toady")] CreatedToday,
-    [Description("View of the last 30 days")]
-    Last30days
-}
\ No newline at end of file
+
diff --git a/src/Application/Features/Loggers/Queries/Specification/LoggerAdvancedFilter.cs b/src/Application/Features/Loggers/Queries/Specification/LoggerAdvancedFilter.cs
new file mode 100644
index 000000000..f70fa05d9
--- /dev/null
+++ b/src/Application/Features/Loggers/Queries/Specification/LoggerAdvancedFilter.cs
@@ -0,0 +1,14 @@
+namespace CleanArchitecture.Blazor.Application.Features.Loggers.Queries.Specification;
+public enum LogListView
+{
+    [Description("All")] All,
+    [Description("Created Toady")] CreatedToday,
+    [Description("View of the last 30 days")]
+    Last30days
+}
+
+public class LoggerAdvancedFilter : PaginationFilter
+{
+    public LogLevel? Level { get; set; }
+    public LogListView ListView { get; set; } = LogListView.All;
+}
diff --git a/src/Application/Features/Loggers/Queries/Specification/LoggerAdvancedSpecification.cs b/src/Application/Features/Loggers/Queries/Specification/LoggerAdvancedSpecification.cs
new file mode 100644
index 000000000..4b520a769
--- /dev/null
+++ b/src/Application/Features/Loggers/Queries/Specification/LoggerAdvancedSpecification.cs
@@ -0,0 +1,22 @@
+using CleanArchitecture.Blazor.Domain.Entities.Logger;
+
+namespace CleanArchitecture.Blazor.Application.Features.Loggers.Queries.Specification;
+
+public class LoggerAdvancedSpecification : Specification<Logger>
+{
+    public LoggerAdvancedSpecification(LoggerAdvancedFilter filter)
+    {
+        var today = DateTime.Now.Date;
+        var start = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
+            CultureInfo.CurrentCulture);
+        var end = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 23:59:59",
+            CultureInfo.CurrentCulture);
+        var last30days =
+            Convert.ToDateTime(today.AddDays(-30).ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
+                CultureInfo.CurrentCulture);
+        Query.Where(p => p.TimeStamp.Date == DateTime.Now.Date, filter.ListView == LogListView.CreatedToday)
+             .Where(p => p.TimeStamp >= last30days, filter.ListView == LogListView.Last30days)
+             .Where(p => p.Level == filter.Level.ToString(), filter.Level is not null)
+             .Where(x => x.Message.Contains(filter.Keyword) || x.Exception.Contains(filter.Keyword) || x.UserName.Contains(filter.Keyword), !string.IsNullOrEmpty(filter.Keyword));
+    }
+}
\ No newline at end of file
diff --git a/src/Application/Features/Products/Queries/Export/ExportProductsQuery.cs b/src/Application/Features/Products/Queries/Export/ExportProductsQuery.cs
index a825f6fd1..e0fc457a9 100644
--- a/src/Application/Features/Products/Queries/Export/ExportProductsQuery.cs
+++ b/src/Application/Features/Products/Queries/Export/ExportProductsQuery.cs
@@ -9,22 +9,10 @@
 
 namespace CleanArchitecture.Blazor.Application.Features.Products.Queries.Export;
 
-public class ExportProductsQuery :  IRequest<Result<byte[]>>
+public class ExportProductsQuery : ProductAdvancedFilter,  IRequest<Result<byte[]>>
 {
-    public string? Name { get; set; }
-    public string? Brand { get; set; }
-    public string? Unit { get; set; }
-    public decimal? MaxPrice { get; set; }
-    public decimal? MinPrice { get; set; }
-    public string? Keyword { get; set; }
-    
-    public string? OrderBy { get; set; }
-    public string? SortDirection { get; set; }
-    public ProductListView ListView { get; set; } = ProductListView.All; //<-- When the user selects a different ListView,
-    public UserProfile? CurrentUser { get; set; } // <-- This CurrentUser property gets its value from the information of
-
     public ExportType ExportType { get; set; }
-    public ExportProductSpecification Specification => new ExportProductSpecification(this);
+    public ProductAdvancedSpecification Specification => new ProductAdvancedSpecification(this);
 }
 
 public class ExportProductsQueryHandler :
diff --git a/src/Application/Features/Products/Queries/Pagination/ProductsPaginationQuery.cs b/src/Application/Features/Products/Queries/Pagination/ProductsPaginationQuery.cs
index 3ccebe65e..75916b524 100644
--- a/src/Application/Features/Products/Queries/Pagination/ProductsPaginationQuery.cs
+++ b/src/Application/Features/Products/Queries/Pagination/ProductsPaginationQuery.cs
@@ -8,16 +8,9 @@
 
 namespace CleanArchitecture.Blazor.Application.Features.Products.Queries.Pagination;
 
-public class ProductsWithPaginationQuery : PaginationFilter, ICacheableRequest<PaginatedData<ProductDto>>
+public class ProductsWithPaginationQuery : ProductAdvancedFilter, ICacheableRequest<PaginatedData<ProductDto>>
 {
-    public string? Name { get; set; }
-    public string? Brand { get; set; }
-    public string? Unit { get; set; }
-    public decimal? MaxPrice { get; set; }
-    public decimal? MinPrice { get; set; }
-    public string? Keyword { get; set; }
-    public ProductListView ListView { get; set; } = ProductListView.All; //<-- When the user selects a different ListView,
-    public UserProfile? CurrentUser { get; set; } // <-- This CurrentUser property gets its value from the information of
+   
 
     public string CacheKey => ProductCacheKey.GetPaginationCacheKey($"{this}");
 
@@ -30,7 +23,7 @@ public override string ToString()
             $"CurrentUser:{CurrentUser?.UserId},ListView:{ListView},Search:{Keyword},Name:{Name},Brand:{Brand},Unit:{Unit},MinPrice:{MinPrice},MaxPrice:{MaxPrice},SortDirection:{SortDirection},OrderBy:{OrderBy},{ PageNumber},{PageSize}";
     }
 
-    public SearchProductSpecification Specification => new SearchProductSpecification(this);
+    public ProductAdvancedSpecification Specification => new ProductAdvancedSpecification(this);
 }
 
 public class ProductsWithPaginationQueryHandler :
diff --git a/src/Application/Features/Products/Queries/Specification/ExportProductSpecification.cs b/src/Application/Features/Products/Queries/Specification/ExportProductSpecification.cs
deleted file mode 100644
index 0bb25af6a..000000000
--- a/src/Application/Features/Products/Queries/Specification/ExportProductSpecification.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using CleanArchitecture.Blazor.Application.Features.Products.Queries.Export;
-
-namespace CleanArchitecture.Blazor.Application.Features.Products.Queries.Specification;
-
-public class ExportProductSpecification : Specification<Product>
-{
-    public ExportProductSpecification(ExportProductsQuery query)
-    {
-        var today = DateTime.Now.Date;
-        var start = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
-            CultureInfo.CurrentCulture);
-        var end = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 23:59:59",
-            CultureInfo.CurrentCulture);
-        var last30day = Convert.ToDateTime(
-            today.AddDays(-30).ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
-            CultureInfo.CurrentCulture);
-        Query.Where(q => q.Name != null)
-             .Where(x => x.Name!.Contains(query.Keyword) || x.Description!.Contains(query.Keyword) ||
-                     x.Brand!.Contains(query.Keyword), !string.IsNullOrEmpty(query.Keyword))
-             .Where(x => x.Name!.Contains(query.Name), !string.IsNullOrEmpty(query.Name))
-             .Where(x => x.Unit == query.Unit, !string.IsNullOrEmpty(query.Unit))
-             .Where(x => x.Brand == query.Brand, !string.IsNullOrEmpty(query.Brand))
-             .Where(x => x.Price <= query.MaxPrice, !string.IsNullOrEmpty(query.Brand))
-             .Where(x => x.Price >= query.MinPrice, query.MinPrice is not null)
-             .Where(product => product.CreatedBy == query.CurrentUser.UserId, query.ListView == ProductListView.My)
-             .Where(product => product.Created >= start && product.Created <= end, query.ListView == ProductListView.CreatedToday)
-             .Where(product => product.Created >= last30day, query.ListView == ProductListView.Created30Days);
-    }
-}
diff --git a/src/Application/Features/Products/Queries/Specification/ProductAdvancedFilter.cs b/src/Application/Features/Products/Queries/Specification/ProductAdvancedFilter.cs
new file mode 100644
index 000000000..5e8e51b82
--- /dev/null
+++ b/src/Application/Features/Products/Queries/Specification/ProductAdvancedFilter.cs
@@ -0,0 +1,12 @@
+namespace CleanArchitecture.Blazor.Application.Features.Products.Queries.Specification;
+public class ProductAdvancedFilter : PaginationFilter
+{
+    public string? Name { get; set; }
+    public string? Brand { get; set; }
+    public string? Unit { get; set; }
+    public decimal? MaxPrice { get; set; }
+    public decimal? MinPrice { get; set; }
+    public string? Keyword { get; set; }
+    public ProductListView ListView { get; set; } = ProductListView.All; //<-- When the user selects a different ListView,
+    public UserProfile? CurrentUser { get; set; } // <-- This CurrentUser property gets its value from the information of
+}
diff --git a/src/Application/Features/Products/Queries/Specification/ProductAdvancedSpecification.cs b/src/Application/Features/Products/Queries/Specification/ProductAdvancedSpecification.cs
new file mode 100644
index 000000000..a303590ba
--- /dev/null
+++ b/src/Application/Features/Products/Queries/Specification/ProductAdvancedSpecification.cs
@@ -0,0 +1,30 @@
+
+namespace CleanArchitecture.Blazor.Application.Features.Products.Queries.Specification;
+
+public class ProductAdvancedSpecification : Specification<Product>
+{
+    public ProductAdvancedSpecification(ProductAdvancedFilter filter)
+    {
+        var today = DateTime.Now.Date;
+        var start = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
+            CultureInfo.CurrentCulture);
+        var end = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 23:59:59",
+            CultureInfo.CurrentCulture);
+        var last30day = Convert.ToDateTime(
+            today.AddDays(-30).ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
+            CultureInfo.CurrentCulture);
+        Query.Where(x => x.Name != null)
+             .Where(x => x.Name!.Contains(filter.Keyword) || x.Description!.Contains(filter.Keyword) ||
+                     x.Brand!.Contains(filter.Keyword), !string.IsNullOrEmpty(filter.Keyword))
+             .Where(x => x.Name!.Contains(filter.Name), !string.IsNullOrEmpty(filter.Name))
+             .Where(x => x.Unit == filter.Unit, !string.IsNullOrEmpty(filter.Unit))
+             .Where(x => x.Brand == filter.Brand, !string.IsNullOrEmpty(filter.Brand))
+             .Where(x => x.Price <= filter.MaxPrice, !string.IsNullOrEmpty(filter.Brand))
+             .Where(x => x.Price >= filter.MinPrice, filter.MinPrice is not null)
+             .Where(x => x.CreatedBy == filter.CurrentUser.UserId, filter.ListView == ProductListView.My)
+             .Where(x => x.Created >= start && x.Created <= end, filter.ListView == ProductListView.CreatedToday)
+             .Where(x => x.Created >= last30day, filter.ListView == ProductListView.Created30Days);
+
+        
+    }
+}
diff --git a/src/Application/Features/Products/Queries/Specification/SearchProductSpecification.cs b/src/Application/Features/Products/Queries/Specification/SearchProductSpecification.cs
deleted file mode 100644
index 64136e135..000000000
--- a/src/Application/Features/Products/Queries/Specification/SearchProductSpecification.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using CleanArchitecture.Blazor.Application.Features.Products.Queries.Pagination;
-
-namespace CleanArchitecture.Blazor.Application.Features.Products.Queries.Specification;
-
-public class SearchProductSpecification : Specification<Product>
-{
-    public SearchProductSpecification(ProductsWithPaginationQuery query)
-    {
-        var today = DateTime.Now.Date;
-        var start = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
-            CultureInfo.CurrentCulture);
-        var end = Convert.ToDateTime(today.ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 23:59:59",
-            CultureInfo.CurrentCulture);
-        var last30day = Convert.ToDateTime(
-            today.AddDays(-30).ToString("yyyy-MM-dd", CultureInfo.CurrentCulture) + " 00:00:00",
-            CultureInfo.CurrentCulture);
-        Query.Where(q => q.Name != null)
-             .Where(x => x.Name!.Contains(query.Keyword) || x.Description!.Contains(query.Keyword) ||
-                     x.Brand!.Contains(query.Keyword), !string.IsNullOrEmpty(query.Keyword))
-             .Where(x => x.Name!.Contains(query.Name), !string.IsNullOrEmpty(query.Name))
-             .Where(x => x.Unit == query.Unit, !string.IsNullOrEmpty(query.Unit))
-             .Where(x => x.Brand == query.Brand, !string.IsNullOrEmpty(query.Brand))
-             .Where(x => x.Price <= query.MaxPrice, !string.IsNullOrEmpty(query.Brand))
-             .Where(x => x.Price >= query.MinPrice, query.MinPrice is not null)
-             .Where(product => product.CreatedBy == query.CurrentUser.UserId, query.ListView == ProductListView.My)
-             .Where(product => product.Created >= start && product.Created <= end, query.ListView == ProductListView.CreatedToday)
-             .Where(product => product.Created >= last30day, query.ListView == ProductListView.Created30Days);
-
-        
-    }
-}
diff --git a/src/Blazor.Server.UI/Pages/Customers/Customers.razor b/src/Blazor.Server.UI/Pages/Customers/Customers.razor
index f4e5134e7..c929a51fd 100644
--- a/src/Blazor.Server.UI/Pages/Customers/Customers.razor
+++ b/src/Blazor.Server.UI/Pages/Customers/Customers.razor
@@ -7,6 +7,7 @@
 @using CleanArchitecture.Blazor.Application.Features.Customers.Commands.Import
 @using CleanArchitecture.Blazor.Application.Features.Customers.Queries.Export
 @using CleanArchitecture.Blazor.Application.Features.Customers.Queries.Pagination
+@using CleanArchitecture.Blazor.Application.Features.Customers.Queries.Specification
 @using CleanArchitecture.Blazor.Application.Features.Customers.Commands.AddEdit
 
 @inherits FluxorComponent
diff --git a/src/Blazor.Server.UI/Pages/Documents/Documents.razor b/src/Blazor.Server.UI/Pages/Documents/Documents.razor
index a6ffb1d42..caec33d5c 100644
--- a/src/Blazor.Server.UI/Pages/Documents/Documents.razor
+++ b/src/Blazor.Server.UI/Pages/Documents/Documents.razor
@@ -11,6 +11,7 @@
 @using CleanArchitecture.Blazor.Application.Features.Documents.Commands.AddEdit
 @using CleanArchitecture.Blazor.Application.Features.Documents.Queries.GetFileStream
 @using CleanArchitecture.Blazor.Application.Features.Documents.Queries.PaginationQuery
+@using CleanArchitecture.Blazor.Application.Features.Documents.Queries.Specification;
 @using CleanArchitecture.Blazor.Application.Features.Fluxor;
 @using CleanArchitecture.Blazor.Infrastructure.Hubs
 
diff --git a/src/Blazor.Server.UI/Pages/SystemManagement/AuditTrails.razor b/src/Blazor.Server.UI/Pages/SystemManagement/AuditTrails.razor
index ea7f32842..bff3f93c7 100644
--- a/src/Blazor.Server.UI/Pages/SystemManagement/AuditTrails.razor
+++ b/src/Blazor.Server.UI/Pages/SystemManagement/AuditTrails.razor
@@ -2,6 +2,7 @@
 @using CleanArchitecture.Blazor.Application.Features.AuditTrails.DTOs
 @using CleanArchitecture.Blazor.Application.Features.AuditTrails.Queries.PaginationQuery
 @using CleanArchitecture.Blazor.Application.Features.AuditTrails.Caching
+@using CleanArchitecture.Blazor.Application.Features.AuditTrails.Queries.Specification;
 
 @inherits FluxorComponent
 @attribute [Authorize(Policy = Permissions.AuditTrails.View)]
diff --git a/src/Blazor.Server.UI/Pages/SystemManagement/Logs.razor b/src/Blazor.Server.UI/Pages/SystemManagement/Logs.razor
index f45a11366..4d723bebf 100644
--- a/src/Blazor.Server.UI/Pages/SystemManagement/Logs.razor
+++ b/src/Blazor.Server.UI/Pages/SystemManagement/Logs.razor
@@ -5,6 +5,7 @@
 @using CleanArchitecture.Blazor.Application.Constants.User
 @using CleanArchitecture.Blazor.Application.Features.Loggers.Commands.Clear
 @using CleanArchitecture.Blazor.Application.Features.Loggers.Queries.PaginationQuery
+@using CleanArchitecture.Blazor.Application.Features.Loggers.Queries.Specification;
 @using FluentEmail.Core
 @using Severity = MudBlazor.Severity