diff --git a/OrderProcessing.ReadModelWorker/Configuration/MongoDbOptions.cs b/OrderProcessing.ReadModelWorker/Configuration/MongoDbOptions.cs
new file mode 100644
index 0000000..21e7fdf
--- /dev/null
+++ b/OrderProcessing.ReadModelWorker/Configuration/MongoDbOptions.cs
@@ -0,0 +1,12 @@
+namespace OrderProcessing.ReadModelWorker.Configuration;
+
+public sealed class MongoDbOptions
+{
+ public const string SectionName = "MongoDb";
+
+ public string ConnectionString { get; set; } = "mongodb://localhost:27017";
+
+ public string DatabaseName { get; set; } = "OrderProcessingReadDb";
+
+ public string OrdersCollectionName { get; set; } = "orders";
+}
\ No newline at end of file
diff --git a/OrderProcessing.ReadModelWorker/OrderProcessing.ReadModelWorker.csproj b/OrderProcessing.ReadModelWorker/OrderProcessing.ReadModelWorker.csproj
new file mode 100644
index 0000000..57d3099
--- /dev/null
+++ b/OrderProcessing.ReadModelWorker/OrderProcessing.ReadModelWorker.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net10.0
+ enable
+ enable
+ dotnet-OrderProcessing.ReadModelWorker-aa56661c-af35-4226-adc4-a3e186dd7a2f
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OrderProcessing.ReadModelWorker/Persistence/MongoDbInitializer.cs b/OrderProcessing.ReadModelWorker/Persistence/MongoDbInitializer.cs
new file mode 100644
index 0000000..e99b9c5
--- /dev/null
+++ b/OrderProcessing.ReadModelWorker/Persistence/MongoDbInitializer.cs
@@ -0,0 +1,48 @@
+using MongoDB.Driver;
+using OrderProcessing.ReadModelWorker.ReadModels;
+
+namespace OrderProcessing.ReadModelWorker.Persistence;
+
+public sealed class MongoDbInitializer : IHostedService
+{
+ private readonly OrderReadModelStore _store;
+ private readonly ILogger _logger;
+
+ public MongoDbInitializer(OrderReadModelStore store, ILogger logger)
+ {
+ _store = store;
+ _logger = logger;
+ }
+
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ var indexes = new[]
+ {
+ new CreateIndexModel(
+ Builders
+ .IndexKeys
+ .Descending(order => order.CreatedAtUtc)),
+
+ new CreateIndexModel(
+ Builders
+ .IndexKeys
+ .Ascending(order => order.CustomerId)
+ .Descending(order => order.CreatedAtUtc)),
+
+ new CreateIndexModel(
+ Builders
+ .IndexKeys
+ .Ascending(order => order.Status)
+ .Descending(order => order.CreatedAtUtc))
+ };
+
+ await _store.Orders.Indexes.CreateManyAsync(indexes, cancellationToken);
+
+ _logger.LogInformation("MongoDB order read-model indexes ensured");
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ return Task.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/OrderProcessing.ReadModelWorker/Persistence/OrderReadModelStore.cs b/OrderProcessing.ReadModelWorker/Persistence/OrderReadModelStore.cs
new file mode 100644
index 0000000..d36ad79
--- /dev/null
+++ b/OrderProcessing.ReadModelWorker/Persistence/OrderReadModelStore.cs
@@ -0,0 +1,20 @@
+using Microsoft.Extensions.Options;
+using MongoDB.Driver;
+using OrderProcessing.ReadModelWorker.Configuration;
+using OrderProcessing.ReadModelWorker.ReadModels;
+
+namespace OrderProcessing.ReadModelWorker.Persistence;
+
+public sealed class OrderReadModelStore
+{
+ public IMongoCollection Orders { get; }
+
+ public OrderReadModelStore(IMongoClient mongoClient, IOptions options)
+ {
+ var mongoOptions = options.Value;
+
+ var database = mongoClient.GetDatabase(mongoOptions.DatabaseName);
+
+ Orders = database.GetCollection(mongoOptions.OrdersCollectionName);
+ }
+}
\ No newline at end of file
diff --git a/OrderProcessing.ReadModelWorker/Program.cs b/OrderProcessing.ReadModelWorker/Program.cs
new file mode 100644
index 0000000..cd1e697
--- /dev/null
+++ b/OrderProcessing.ReadModelWorker/Program.cs
@@ -0,0 +1,31 @@
+using Microsoft.Extensions.Options;
+using MongoDB.Driver;
+using OrderProcessing.ReadModelWorker.Configuration;
+using OrderProcessing.ReadModelWorker.Persistence;
+
+var builder = Host.CreateApplicationBuilder(args);
+
+builder.Services.AddOptions()
+ .Bind(builder.Configuration.GetSection(MongoDbOptions.SectionName))
+ .Validate(options => !string.IsNullOrWhiteSpace(options.ConnectionString),
+ "MongoDB connection string is required.")
+ .Validate(options => !string.IsNullOrWhiteSpace(options.DatabaseName),
+ "MongoDB database name is required.")
+ .Validate(options => !string.IsNullOrWhiteSpace(options.OrdersCollectionName),
+ "MongoDB orders collection name is required.")
+ .ValidateOnStart();
+
+builder.Services.AddSingleton(serviceProvider =>
+ {
+ var options = serviceProvider.GetRequiredService>().Value;
+
+ return new MongoClient(options.ConnectionString);
+ });
+
+builder.Services.AddHostedService();
+
+builder.Services.AddSingleton();
+
+var host = builder.Build();
+
+await host.RunAsync();
\ No newline at end of file
diff --git a/OrderProcessing.ReadModelWorker/Properties/launchSettings.json b/OrderProcessing.ReadModelWorker/Properties/launchSettings.json
new file mode 100644
index 0000000..f981c90
--- /dev/null
+++ b/OrderProcessing.ReadModelWorker/Properties/launchSettings.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "OrderProcessing.ReadModelWorker": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "environmentVariables": {
+ "DOTNET_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/OrderProcessing.ReadModelWorker/ReadModels/OrderItemReadModel.cs b/OrderProcessing.ReadModelWorker/ReadModels/OrderItemReadModel.cs
new file mode 100644
index 0000000..1a38816
--- /dev/null
+++ b/OrderProcessing.ReadModelWorker/ReadModels/OrderItemReadModel.cs
@@ -0,0 +1,14 @@
+namespace OrderProcessing.ReadModelWorker.ReadModels;
+
+public sealed class OrderItemReadModel
+{
+ public int ProductId { get; set; }
+
+ public required string ProductName { get; set; }
+
+ public int Quantity { get; set; }
+
+ public decimal UnitPrice { get; set; }
+
+ public decimal LineTotal { get; set; }
+}
\ No newline at end of file
diff --git a/OrderProcessing.ReadModelWorker/ReadModels/OrderReadModel.cs b/OrderProcessing.ReadModelWorker/ReadModels/OrderReadModel.cs
new file mode 100644
index 0000000..7db2ded
--- /dev/null
+++ b/OrderProcessing.ReadModelWorker/ReadModels/OrderReadModel.cs
@@ -0,0 +1,27 @@
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace OrderProcessing.ReadModelWorker.ReadModels;
+
+public sealed class OrderReadModel
+{
+ [BsonId]
+ public int OrderId { get; set; }
+
+ public int CustomerId { get; set; }
+
+ public required string CustomerName { get; set; }
+
+ public required string Status { get; set; }
+
+ public decimal TotalAmount { get; set; }
+
+ public DateTime CreatedAtUtc { get; set; }
+
+ public DateTime? CompletedAtUtc { get; set; }
+
+ public DateTime? CancelledAtUtc { get; set; }
+
+ public List Items { get; set; } = [];
+
+ public DateTime LastUpdatedAtUtc { get; set; }
+}
\ No newline at end of file
diff --git a/OrderProcessing.ReadModelWorker/appsettings.Development.json b/OrderProcessing.ReadModelWorker/appsettings.Development.json
new file mode 100644
index 0000000..b2dcdb6
--- /dev/null
+++ b/OrderProcessing.ReadModelWorker/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/OrderProcessing.ReadModelWorker/appsettings.json b/OrderProcessing.ReadModelWorker/appsettings.json
new file mode 100644
index 0000000..47c79fc
--- /dev/null
+++ b/OrderProcessing.ReadModelWorker/appsettings.json
@@ -0,0 +1,13 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "MongoDb": {
+ "ConnectionString": "mongodb://localhost:27017",
+ "DatabaseName": "OrderProcessingReadDb",
+ "OrdersCollectionName": "orders"
+ }
+}
diff --git a/OrderProcessingPlatform.slnx b/OrderProcessingPlatform.slnx
index c1d1b00..92c5ba9 100644
--- a/OrderProcessingPlatform.slnx
+++ b/OrderProcessingPlatform.slnx
@@ -6,4 +6,5 @@
+