diff --git a/StreamManagement/Form1.Designer.cs b/StreamManagement/Form1.Designer.cs
new file mode 100644
index 0000000..97c06df
--- /dev/null
+++ b/StreamManagement/Form1.Designer.cs
@@ -0,0 +1,71 @@
+namespace StreamManagement
+{
+ partial class Form1
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ StreamSelectionList = new ComboBox();
+ label1 = new Label();
+ SuspendLayout();
+ //
+ // StreamSelectionList
+ //
+ StreamSelectionList.FormattingEnabled = true;
+ StreamSelectionList.Location = new Point(93, 22);
+ StreamSelectionList.Name = "StreamSelectionList";
+ StreamSelectionList.Size = new Size(300, 23);
+ StreamSelectionList.TabIndex = 0;
+ //
+ // label1
+ //
+ label1.AutoSize = true;
+ label1.Location = new Point(33, 25);
+ label1.Name = "label1";
+ label1.Size = new Size(44, 15);
+ label1.TabIndex = 1;
+ label1.Text = "Stream";
+ //
+ // Form1
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(800, 450);
+ Controls.Add(label1);
+ Controls.Add(StreamSelectionList);
+ Name = "Form1";
+ Text = "Form1";
+ Load += Form1_Load;
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private ComboBox StreamSelectionList;
+ private Label label1;
+ }
+}
diff --git a/StreamManagement/Form1.cs b/StreamManagement/Form1.cs
new file mode 100644
index 0000000..76c60a6
--- /dev/null
+++ b/StreamManagement/Form1.cs
@@ -0,0 +1,41 @@
+using System.Text.Json;
+
+namespace StreamManagement
+{
+ public partial class Form1 : Form
+ {
+ public Form1()
+ {
+ InitializeComponent();
+ }
+
+ private async void Form1_Load(object sender, EventArgs e)
+ {
+ // Load up the configuration
+ var streamConfiguration = await LoadStreamConfig(CancellationToken.None);
+
+ // Add the streams to a Drop Down
+ foreach (StreamConfiguration configuration in streamConfiguration) {
+ this.StreamSelectionList.Items.Add(configuration.StreamName);
+ }
+ }
+
+ private static async Task> LoadStreamConfig(CancellationToken cancellationToken)
+ {
+ // Read the identity server config json string
+ String streamConfigurationJsonData = null;
+ using (StreamReader sr = new StreamReader("streamconfiguration.json"))
+ {
+ streamConfigurationJsonData = await sr.ReadToEndAsync(cancellationToken);
+ }
+
+ StreamConfigurationList streamConfiguration = JsonSerializer.Deserialize(streamConfigurationJsonData);
+
+ return streamConfiguration.StreamConfiguration;
+ }
+ }
+
+ public record StreamConfigurationList(List StreamConfiguration);
+
+ public record StreamConfiguration(String StreamName, Int32 MaxAgeInDays);
+}
diff --git a/StreamManagement/Form1.resx b/StreamManagement/Form1.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/StreamManagement/Form1.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/StreamManagement/Program.cs b/StreamManagement/Program.cs
new file mode 100644
index 0000000..95b4ef8
--- /dev/null
+++ b/StreamManagement/Program.cs
@@ -0,0 +1,17 @@
+namespace StreamManagement
+{
+ internal static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ ApplicationConfiguration.Initialize();
+ Application.Run(new Form1());
+ }
+ }
+}
\ No newline at end of file
diff --git a/StreamManagement/StreamManagement.csproj b/StreamManagement/StreamManagement.csproj
new file mode 100644
index 0000000..8671b43
--- /dev/null
+++ b/StreamManagement/StreamManagement.csproj
@@ -0,0 +1,17 @@
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ true
+ enable
+
+
+
+
+ Always
+
+
+
+
\ No newline at end of file
diff --git a/StreamManagement/streamconfiguration.json b/StreamManagement/streamconfiguration.json
new file mode 100644
index 0000000..1d1e912
--- /dev/null
+++ b/StreamManagement/streamconfiguration.json
@@ -0,0 +1,12 @@
+{
+ "StreamConfiguration": [
+ {
+ "StreamName": "$ce-OperatorAggreate",
+ "MaxAgeInDays": 30
+ },
+ {
+ "StreamName": "$ce-MerchantAggreate",
+ "MaxAgeInDays": 30
+ }
+ ]
+}
\ No newline at end of file
diff --git a/StreamManagementTool/Program.cs b/StreamManagementTool/Program.cs
new file mode 100644
index 0000000..fd5e7cc
--- /dev/null
+++ b/StreamManagementTool/Program.cs
@@ -0,0 +1,65 @@
+using System.Text.Json;
+using EventStore.Client;
+using Microsoft.Extensions.Configuration;
+using Shared.General;
+
+namespace StreamManagementTool
+{
+ internal class Program
+ {
+ static async Task Main(string[] args) {
+ IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
+ IConfigurationRoot configurationRoot = builder.Build();
+ ConfigurationReader.Initialise(configurationRoot);
+
+ List config = await LoadStreamConfig(CancellationToken.None);
+ EventStoreClientSettings settings = EventStoreClientSettings.Create(ConfigurationReader.GetValue("AppSettings", "EventStoreAddress"));
+ EventStoreClient client = new EventStoreClient(settings);
+
+ foreach (StreamConfiguration streamConfiguration in config) {
+ // Fetch existing metadata
+
+ var existingMetadataResult = await client.GetStreamMetadataAsync(streamConfiguration.StreamName);
+
+ // Check if metadata exists
+ var existingMetadata = existingMetadataResult.Metadata;
+
+ // Create a new metadata object, updating maxAge to 60 days
+ var updatedMetadata = new StreamMetadata(
+ maxAge: TimeSpan.FromDays(streamConfiguration.MaxAgeInDays),
+ maxCount: existingMetadata.MaxCount, // Preserve existing maxCount
+ truncateBefore: existingMetadata.TruncateBefore, // Preserve existing truncateBefore
+ cacheControl: existingMetadata.CacheControl, // Preserve cacheControl
+ customMetadata: existingMetadata.CustomMetadata // Preserve custom metadata
+ );
+
+ // Set the updated metadata
+ await client.SetStreamMetadataAsync(
+ streamName: streamConfiguration.StreamName,
+ expectedRevision: new StreamRevision(existingMetadataResult.MetastreamRevision.GetValueOrDefault()),
+ metadata: updatedMetadata
+ );
+
+ Console.WriteLine($"Stream {streamConfiguration.StreamName} metadata updated successfully. Max Age is {streamConfiguration.MaxAgeInDays} days");
+ }
+ }
+
+ private static async Task> LoadStreamConfig(CancellationToken cancellationToken)
+ {
+ // Read the identity server config json string
+ String streamConfigurationJsonData = null;
+ using (StreamReader sr = new StreamReader("streammanagementconfiguration.json"))
+ {
+ streamConfigurationJsonData = await sr.ReadToEndAsync(cancellationToken);
+ }
+
+ StreamConfigurationList streamConfiguration = JsonSerializer.Deserialize(streamConfigurationJsonData);
+
+ return streamConfiguration.StreamConfiguration;
+ }
+ }
+
+ public record StreamConfigurationList(List StreamConfiguration);
+
+ public record StreamConfiguration(String StreamName, Int32 MaxAgeInDays);
+}
diff --git a/StreamManagementTool/StreamManagementTool.csproj b/StreamManagementTool/StreamManagementTool.csproj
new file mode 100644
index 0000000..aa22305
--- /dev/null
+++ b/StreamManagementTool/StreamManagementTool.csproj
@@ -0,0 +1,26 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+
+
diff --git a/StreamManagementTool/StreamManagementTool.sln b/StreamManagementTool/StreamManagementTool.sln
new file mode 100644
index 0000000..9a4023e
--- /dev/null
+++ b/StreamManagementTool/StreamManagementTool.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.12.35527.113 d17.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamManagementTool", "StreamManagementTool.csproj", "{01D46465-2E16-4E65-BB82-55942079C4F6}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {01D46465-2E16-4E65-BB82-55942079C4F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {01D46465-2E16-4E65-BB82-55942079C4F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {01D46465-2E16-4E65-BB82-55942079C4F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {01D46465-2E16-4E65-BB82-55942079C4F6}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/StreamManagementTool/appsettings.json b/StreamManagementTool/appsettings.json
new file mode 100644
index 0000000..39391d5
--- /dev/null
+++ b/StreamManagementTool/appsettings.json
@@ -0,0 +1,13 @@
+{
+ "AppSettings": {
+ // Local (Docker)
+ "EventStoreAddress": "esdb://admin:changeit@127.0.0.1:4113?tls=false&tlsVerifyCert=false"
+
+ // Staging
+ //"EventStoreAddress": "esdb://admin:changeit@192.168.1.167:2113?tls=false&tlsVerifyCert=false"
+ //"EventStoreAddress": "esdb://admin:changeit@192.168.1.157:2113?tls=false&tlsVerifyCert=false"
+
+ // Production
+ //"EventStoreAddress": "esdb://admin:changeit@192.168.1.155:2113?tls=false&tlsVerifyCert=false"
+ }
+}
diff --git a/StreamManagementTool/streammanagementconfiguration.json b/StreamManagementTool/streammanagementconfiguration.json
new file mode 100644
index 0000000..9f3d022
--- /dev/null
+++ b/StreamManagementTool/streammanagementconfiguration.json
@@ -0,0 +1,8 @@
+{
+ "StreamConfiguration": [
+ {
+ "StreamName": "$ce-OperatorAggregate",
+ "MaxAgeInDays": 30
+ }
+ ]
+}
\ No newline at end of file