diff --git a/src/DigitalData.EmailProfiler.Application/Common/Interfaces/ICommandPublisher.cs b/src/DigitalData.EmailProfiler.Application/Common/Interfaces/ICommandPublisher.cs
new file mode 100644
index 0000000..e63c4e3
--- /dev/null
+++ b/src/DigitalData.EmailProfiler.Application/Common/Interfaces/ICommandPublisher.cs
@@ -0,0 +1,19 @@
+using MediatR;
+
+namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
+
+///
+/// Interface for publishing commands to a message broker (e.g., RabbitMQ)
+///
+public interface ICommandPublisher
+{
+ ///
+ /// Publishes a command to the message broker for asynchronous processing
+ ///
+ /// The command type (must implement IRequest)
+ /// The command to publish
+ /// Cancellation token
+ /// Task representing the publish operation
+ Task PublishAsync(TCommand command, CancellationToken cancellationToken = default)
+ where TCommand : IRequest;
+}
diff --git a/src/DigitalData.EmailProfiler.Application/DependencyInjection.cs b/src/DigitalData.EmailProfiler.Application/DependencyInjection.cs
new file mode 100644
index 0000000..52d918d
--- /dev/null
+++ b/src/DigitalData.EmailProfiler.Application/DependencyInjection.cs
@@ -0,0 +1,30 @@
+using System.Reflection;
+using FluentValidation;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace DigitalData.EmailProfiler.Application;
+
+///
+/// Dependency injection configuration for Application layer.
+///
+public static class DependencyInjection
+{
+ public static IServiceCollection AddApplicationServices(this IServiceCollection services)
+ {
+ var assembly = Assembly.GetExecutingAssembly();
+
+ // MediatR - Register all handlers
+ services.AddMediatR(config =>
+ {
+ config.RegisterServicesFromAssembly(assembly);
+ });
+
+ // AutoMapper - Register all profiles
+ services.AddAutoMapper(assembly);
+
+ // FluentValidation - Register all validators
+ services.AddValidatorsFromAssembly(assembly);
+
+ return services;
+ }
+}
diff --git a/src/DigitalData.EmailProfiler.Application/Interfaces/Repositories/IRepository.cs b/src/DigitalData.EmailProfiler.Application/Interfaces/Repositories/IRepository.cs
index 32ab791..7c77631 100644
--- a/src/DigitalData.EmailProfiler.Application/Interfaces/Repositories/IRepository.cs
+++ b/src/DigitalData.EmailProfiler.Application/Interfaces/Repositories/IRepository.cs
@@ -3,17 +3,58 @@ using System.Linq.Expressions;
namespace DigitalData.EmailProfiler.Application.Interfaces.Repositories;
///
-/// Base repository interface for common CRUD operations.
+/// Base repository interface for common CRUD operations with AutoMapper support.
+/// Changes are automatically saved after each operation - no explicit SaveChanges needed.
///
-/// Entity type
-public interface IRepository where T : class
+/// Entity type
+public interface IRepository where TEntity : class
{
- Task GetByIdAsync(int id, CancellationToken cancellationToken = default);
- Task> GetAllAsync(CancellationToken cancellationToken = default);
- Task> FindAsync(Expression> predicate, CancellationToken cancellationToken = default);
- Task AddAsync(T entity, CancellationToken cancellationToken = default);
- Task UpdateAsync(T entity, CancellationToken cancellationToken = default);
- Task DeleteAsync(T entity, CancellationToken cancellationToken = default);
- Task ExistsAsync(Expression> predicate, CancellationToken cancellationToken = default);
- Task CountAsync(Expression>? predicate = null, CancellationToken cancellationToken = default);
+ // ==================== QUERY OPERATIONS ====================
+
+ Task GetByIdAsync(int id, CancellationToken cancellationToken = default);
+ Task> GetAllAsync(CancellationToken cancellationToken = default);
+ Task> FindAsync(Expression> predicate, CancellationToken cancellationToken = default);
+ Task FirstOrDefaultAsync(Expression> predicate, CancellationToken cancellationToken = default);
+ Task ExistsAsync(Expression> predicate, CancellationToken cancellationToken = default);
+ Task CountAsync(Expression>? predicate = null, CancellationToken cancellationToken = default);
+
+ // ==================== CREATE OPERATIONS ====================
+
+ ///
+ /// Create entity from DTO using AutoMapper and save immediately.
+ ///
+ /// Created entity with ID populated
+ Task CreateAsync(TDto dto, CancellationToken cancellationToken = default) where TDto : class;
+
+ // ==================== UPDATE OPERATIONS ====================
+
+ ///
+ /// Update ALL entities matching expression using DTO via AutoMapper.
+ /// WARNING: This can update multiple records. Use UpdateSingleAsync for single-record updates.
+ ///
+ /// Number of entities updated
+ Task UpdateAsync(Expression> predicate, TDto dto, CancellationToken cancellationToken = default) where TDto : class;
+
+ ///
+ /// Update SINGLE entity matching expression using DTO via AutoMapper.
+ /// SAFETY: Throws exception if zero or multiple entities match the predicate.
+ ///
+ /// Thrown when zero or multiple entities match
+ Task UpdateSingleAsync(Expression> predicate, TDto dto, CancellationToken cancellationToken = default) where TDto : class;
+
+ // ==================== DELETE OPERATIONS ====================
+
+ ///
+ /// Delete ALL entities matching expression.
+ /// WARNING: This can delete multiple records. Use DeleteSingleAsync for single-record deletes.
+ ///
+ /// Number of entities deleted
+ Task DeleteAsync(Expression> predicate, CancellationToken cancellationToken = default);
+
+ ///
+ /// Delete SINGLE entity matching expression.
+ /// SAFETY: Throws exception if zero or multiple entities match the predicate.
+ ///
+ /// Thrown when zero or multiple entities match
+ Task DeleteSingleAsync(Expression> predicate, CancellationToken cancellationToken = default);
}
diff --git a/src/DigitalData.EmailProfiler.Application/Interfaces/Repositories/IUnitOfWork.cs b/src/DigitalData.EmailProfiler.Application/Interfaces/Repositories/IUnitOfWork.cs
deleted file mode 100644
index 58d9c9d..0000000
--- a/src/DigitalData.EmailProfiler.Application/Interfaces/Repositories/IUnitOfWork.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-namespace DigitalData.EmailProfiler.Application.Interfaces.Repositories;
-
-///
-/// Unit of Work pattern for transaction management.
-///
-public interface IUnitOfWork : IDisposable
-{
- IEmailAccountRepository EmailAccounts { get; }
- IEmailProfileRepository EmailProfiles { get; }
- IEmailProcessRepository EmailProcesses { get; }
- IEmailHistoryRepository EmailHistories { get; }
- IEmailOutboxRepository EmailOutbox { get; }
-
- ///
- /// Save all changes to the database.
- ///
- Task SaveChangesAsync(CancellationToken cancellationToken = default);
-
- ///
- /// Begin a database transaction.
- ///
- Task BeginTransactionAsync(CancellationToken cancellationToken = default);
-
- ///
- /// Commit the current transaction.
- ///
- Task CommitTransactionAsync(CancellationToken cancellationToken = default);
-
- ///
- /// Rollback the current transaction.
- ///
- Task RollbackTransactionAsync(CancellationToken cancellationToken = default);
-}