diff --git a/src/Workflow/StellaOps.Workflow.slnx b/src/Workflow/StellaOps.Workflow.slnx
index 67e2f4912..008e298d5 100644
--- a/src/Workflow/StellaOps.Workflow.slnx
+++ b/src/Workflow/StellaOps.Workflow.slnx
@@ -14,6 +14,11 @@
+
+
+
+
+
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/IWorkflowActorRoleResolver.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/IWorkflowActorRoleResolver.cs
new file mode 100644
index 000000000..7a9fd0f77
--- /dev/null
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/IWorkflowActorRoleResolver.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace StellaOps.Workflow.Abstractions;
+
+///
+/// Resolves the authenticated actor's identity (ID + roles) from the server-side
+/// request context. Implementations may query a database, read JWT claims, or
+/// fall back to client-supplied values.
+///
+public interface IWorkflowActorRoleResolver
+{
+ ///
+ /// Returns the actor ID for the current request.
+ /// Implementations should prefer server-side identity over client-supplied values.
+ ///
+ string ResolveActorId(string? clientActorId);
+
+ ///
+ /// Resolves user roles from a trusted source (database, identity provider).
+ /// Falls back to when no server-side context
+ /// is available (e.g., during signal pump processing).
+ ///
+ Task> ResolveActorRolesAsync(
+ string actorId,
+ IReadOnlyCollection? clientRoles,
+ CancellationToken cancellationToken = default);
+}
+
+///
+/// Default no-op resolver that passes through client-supplied values.
+/// Used when no database-backed role resolution is configured.
+///
+public sealed class NullWorkflowActorRoleResolver : IWorkflowActorRoleResolver
+{
+ public string ResolveActorId(string? clientActorId)
+ => clientActorId ?? string.Empty;
+
+ public Task> ResolveActorRolesAsync(
+ string actorId,
+ IReadOnlyCollection? clientRoles,
+ CancellationToken cancellationToken = default)
+ => Task.FromResult>(clientRoles ?? []);
+}
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowCanonicalDefinitionCompiler.Helpers.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowCanonicalDefinitionCompiler.Helpers.cs
index a39bde064..915e74b1e 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowCanonicalDefinitionCompiler.Helpers.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowCanonicalDefinitionCompiler.Helpers.cs
@@ -179,8 +179,10 @@ public static partial class WorkflowCanonicalDefinitionCompiler
},
ResultKey = resultKey,
TimeoutSeconds = timeoutSeconds,
- WhenFailure = failureHandlers?.HasFailureBranch == true ? BuildSequence(failureHandlers.WhenFailure) : null,
- WhenTimeout = failureHandlers?.HasTimeoutBranch == true ? BuildSequence(failureHandlers.WhenTimeout) : null,
+ // Preserve empty handlers (0 steps) as empty sequences — they mean "ignore failure and continue".
+ // Only set to null when no handler was provided at all.
+ WhenFailure = failureHandlers is not null ? BuildSequence(failureHandlers.WhenFailure) : null,
+ WhenTimeout = failureHandlers is not null ? BuildSequence(failureHandlers.WhenTimeout) : null,
};
}
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowCanonicalExpressionRuntime.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowCanonicalExpressionRuntime.cs
index fabb7c215..7e53dbb07 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowCanonicalExpressionRuntime.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowCanonicalExpressionRuntime.cs
@@ -480,10 +480,12 @@ public static class WorkflowCanonicalExpressionRuntime
JsonValueKind.Number when element.TryGetInt64(out var int64Value) => int64Value,
JsonValueKind.Number when element.TryGetDecimal(out var decimalValue) => decimalValue,
JsonValueKind.Number when element.TryGetDouble(out var doubleValue) => doubleValue,
- JsonValueKind.Object => element.EnumerateObject().ToDictionary(
- x => x.Name,
- x => ToRuntimeValue(x.Value),
- StringComparer.OrdinalIgnoreCase),
+ JsonValueKind.Object => element.EnumerateObject()
+ .GroupBy(x => x.Name, StringComparer.OrdinalIgnoreCase)
+ .ToDictionary(
+ g => g.Key,
+ g => ToRuntimeValue(g.Last().Value),
+ StringComparer.OrdinalIgnoreCase),
JsonValueKind.Array => element.EnumerateArray().Select(ToRuntimeValue).ToArray(),
_ => element.ToString(),
};
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowDeclarativeAbstractions.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowDeclarativeAbstractions.cs
index 7d373c17f..8ba98212b 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowDeclarativeAbstractions.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowDeclarativeAbstractions.cs
@@ -726,6 +726,104 @@ public sealed class WorkflowFlowBuilder
null);
}
+ public WorkflowFlowBuilder Call(
+ string stepName,
+ Address address,
+ WorkflowExpressionDefinition payloadExpression,
+ Action> whenFailure,
+ Action>? whenTimeout = null)
+ {
+ return AddMicroserviceCall(
+ stepName,
+ address.MicroserviceName,
+ address.Command,
+ context => WorkflowCanonicalExpressionRuntime.Evaluate(payloadExpression, context),
+ payloadExpression,
+ null,
+ whenFailure,
+ whenTimeout);
+ }
+
+ public WorkflowFlowBuilder Call(
+ string stepName,
+ Address address,
+ WorkflowExpressionDefinition payloadExpression,
+ WorkflowHandledBranchAction onFailure,
+ WorkflowHandledBranchAction onTimeout = WorkflowHandledBranchAction.None)
+ {
+ return AddMicroserviceCall(
+ stepName,
+ address.MicroserviceName,
+ address.Command,
+ context => WorkflowCanonicalExpressionRuntime.Evaluate(payloadExpression, context),
+ payloadExpression,
+ null,
+ null,
+ null,
+ onFailure,
+ onTimeout);
+ }
+
+ public WorkflowFlowBuilder Call(
+ string stepName,
+ Address address,
+ WorkflowExpressionDefinition payloadExpression,
+ string? resultKey = null)
+ {
+ ArgumentNullException.ThrowIfNull(payloadExpression);
+ return AddMicroserviceCall(
+ stepName,
+ address.MicroserviceName,
+ address.Command,
+ context => WorkflowCanonicalExpressionRuntime.Evaluate(payloadExpression, context),
+ payloadExpression,
+ resultKey ?? stepName,
+ null,
+ null);
+ }
+
+ public WorkflowFlowBuilder Call(
+ string stepName,
+ Address address,
+ WorkflowExpressionDefinition payloadExpression,
+ Action> whenFailure,
+ Action>? whenTimeout = null,
+ string? resultKey = null)
+ {
+ ArgumentNullException.ThrowIfNull(payloadExpression);
+ return AddMicroserviceCall(
+ stepName,
+ address.MicroserviceName,
+ address.Command,
+ context => WorkflowCanonicalExpressionRuntime.Evaluate(payloadExpression, context),
+ payloadExpression,
+ resultKey,
+ whenFailure,
+ whenTimeout);
+ }
+
+ public WorkflowFlowBuilder Call(
+ string stepName,
+ Address address,
+ WorkflowExpressionDefinition payloadExpression,
+ WorkflowHandledBranchAction onFailure,
+ WorkflowHandledBranchAction onTimeout = WorkflowHandledBranchAction.None,
+ string? resultKey = null)
+ {
+ ArgumentNullException.ThrowIfNull(payloadExpression);
+ return AddMicroserviceCall(
+ stepName,
+ address.MicroserviceName,
+ address.Command,
+ context => WorkflowCanonicalExpressionRuntime.Evaluate(payloadExpression, context),
+ payloadExpression,
+ resultKey,
+ null,
+ null,
+ onFailure,
+ onTimeout);
+ }
+
public WorkflowFlowBuilder Call(
string stepName,
Address address,
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowExecutionActorContext.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowExecutionActorContext.cs
new file mode 100644
index 000000000..871ce857f
--- /dev/null
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowExecutionActorContext.cs
@@ -0,0 +1,35 @@
+using System.Threading;
+
+namespace StellaOps.Workflow.Abstractions;
+
+///
+/// Propagates the authenticated actor ID through async workflow execution chains
+/// (e.g., OnComplete -> Call -> transport) where the original request context
+/// is not available. Implementations set ActorId and CallerUserId during
+/// task-complete/start-workflow processing.
+///
+public sealed class WorkflowExecutionActorContext
+{
+ private static readonly AsyncLocal CurrentActorId = new();
+ private static readonly AsyncLocal CurrentCallerUserId = new();
+
+ ///
+ /// The actor ID from the task operation request (e.g., numeric user account ID).
+ /// Used for role resolution and task assignment.
+ ///
+ public string? ActorId
+ {
+ get => CurrentActorId.Value;
+ set => CurrentActorId.Value = value;
+ }
+
+ ///
+ /// The authenticated caller's user ID extracted from the HTTP request context.
+ /// Used by transport implementations for backend service calls.
+ ///
+ public string? CallerUserId
+ {
+ get => CurrentCallerUserId.Value;
+ set => CurrentCallerUserId.Value = value;
+ }
+}
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowRegistrationAbstractions.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowRegistrationAbstractions.cs
index 770d41846..e0d8cd899 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowRegistrationAbstractions.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Abstractions/WorkflowRegistrationAbstractions.cs
@@ -78,6 +78,10 @@ public static class WorkflowRegistrationServiceCollectionExtensions
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web)
{
PropertyNameCaseInsensitive = true,
+ // Allow floating-point JSON numbers (e.g., 201000256548.0) to deserialize into integer
+ // types (long?, int?). This is needed because the workflow state round-trips through
+ // JSON serialization which may add ".0" to integer values.
+ NumberHandling = global::System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString,
};
public static IServiceCollection AddWorkflowRegistration(
@@ -190,7 +194,11 @@ public static class WorkflowRegistrationServiceCollectionExtensions
return new Dictionary(payload, StringComparer.OrdinalIgnoreCase);
}
- var json = JsonSerializer.Serialize(payload, SerializerOptions);
+ // Normalize decimal-valued integers (e.g., 201000256548.0 → 201000256548)
+ // before serialization. This is needed because the workflow state may store
+ // integer values as decimals after JSON round-trips.
+ var normalized = NormalizePayloadNumbers(payload);
+ var json = JsonSerializer.Serialize(normalized, SerializerOptions);
return JsonSerializer.Deserialize(json, startRequestType, SerializerOptions)
?? throw new InvalidOperationException(
$"Unable to bind workflow payload to '{startRequestType.FullName}'.");
@@ -291,5 +299,27 @@ public static class WorkflowRegistrationServiceCollectionExtensions
};
}
+ private static IDictionary NormalizePayloadNumbers(IDictionary payload)
+ {
+ var result = new Dictionary(payload.Count, StringComparer.OrdinalIgnoreCase);
+ foreach (var kvp in payload)
+ {
+ result[kvp.Key] = NormalizeValue(kvp.Value);
+ }
+ return result;
+ }
+
+ private static object? NormalizeValue(object? value)
+ {
+ return value switch
+ {
+ decimal d when d == Math.Truncate(d) && d >= long.MinValue && d <= long.MaxValue => (long)d,
+ double d when d == Math.Truncate(d) && d >= long.MinValue && d <= long.MaxValue => (long)d,
+ IDictionary dict => NormalizePayloadNumbers(dict),
+ object[] arr => arr.Select(NormalizeValue).ToArray(),
+ _ => value,
+ };
+ }
+
private sealed record WorkflowBusinessReferencePartProperty(PropertyInfo Property, string PartName);
}
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowStartContracts.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowStartContracts.cs
index 8c4d3716e..bf9270c83 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowStartContracts.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowStartContracts.cs
@@ -16,4 +16,6 @@ public sealed record StartWorkflowResponse
public required string WorkflowName { get; init; }
public required string WorkflowVersion { get; init; }
public WorkflowBusinessReference? BusinessReference { get; init; }
+ public IReadOnlyCollection NextTasks { get; init; } = [];
+ public IDictionary WorkflowState { get; init; } = new Dictionary();
}
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowTaskContracts.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowTaskContracts.cs
index 0df8f01ac..06e080f81 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowTaskContracts.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowTaskContracts.cs
@@ -87,6 +87,9 @@ public sealed record WorkflowTaskCompleteResponse
{
public required string WorkflowTaskId { get; init; }
public required bool Completed { get; init; }
+ public string? WorkflowInstanceId { get; init; }
+ public IReadOnlyCollection NextTasks { get; init; } = [];
+ public IDictionary WorkflowState { get; init; } = new Dictionary();
}
public sealed record WorkflowTaskAssignRequest
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.Oracle/OracleWorkflowDataStoreExtensions.cs b/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.Oracle/OracleWorkflowDataStoreExtensions.cs
index c39a268a7..792a310dd 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.Oracle/OracleWorkflowDataStoreExtensions.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.Oracle/OracleWorkflowDataStoreExtensions.cs
@@ -1,5 +1,6 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.EntityFrameworkCore;
using StellaOps.Workflow.Abstractions;
@@ -10,10 +11,27 @@ public static class OracleWorkflowDataStoreExtensions
public static IServiceCollection AddWorkflowOracleDataStore(
this IServiceCollection services, IConfiguration configuration)
{
- // Register WorkflowDbContext with Oracle provider
- // Register OracleWorkflowRuntimeStateStore
- // Register OracleWorkflowHostedJobLockService
- // Register EF-based projection/retention stores
+ services.AddWorkflowModule("workflow-store.oracle", "1.0.0");
+ services.AddSingleton(
+ new WorkflowBackendRegistrationMarker(WorkflowBackendNames.Oracle));
+
+ if (!string.Equals(configuration.GetWorkflowBackendProvider(), WorkflowBackendNames.Oracle, StringComparison.OrdinalIgnoreCase))
+ {
+ return services;
+ }
+
+ services.AddDbContext(options =>
+ {
+ var connectionString = configuration.GetConnectionString("WorkflowOracle")
+ ?? configuration.GetConnectionString("Default");
+ if (!string.IsNullOrWhiteSpace(connectionString))
+ {
+ options.UseOracle(connectionString);
+ }
+ });
+ services.Replace(ServiceDescriptor.Scoped());
+ services.Replace(ServiceDescriptor.Scoped());
+
return services;
}
}
diff --git a/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Mongo/ServiceRegistrator.cs b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Mongo/ServiceRegistrator.cs
new file mode 100644
index 000000000..024b1e762
--- /dev/null
+++ b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Mongo/ServiceRegistrator.cs
@@ -0,0 +1,16 @@
+using StellaOps.DependencyInjection;
+using StellaOps.Workflow.Abstractions;
+using StellaOps.Workflow.DataStore.MongoDB;
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace StellaOps.Workflow.Plugin.WorkflowStore.Mongo;
+
+public sealed class ServiceRegistrator : IDependencyInjectionRoutine
+{
+ public IServiceCollection Register(IServiceCollection services, IConfiguration configuration)
+ {
+ return services.AddWorkflowMongoDataStore(configuration);
+ }
+}
diff --git a/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Mongo/StellaOps.Workflow.Plugin.WorkflowStore.Mongo.csproj b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Mongo/StellaOps.Workflow.Plugin.WorkflowStore.Mongo.csproj
new file mode 100644
index 000000000..84a3614d3
--- /dev/null
+++ b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Mongo/StellaOps.Workflow.Plugin.WorkflowStore.Mongo.csproj
@@ -0,0 +1,37 @@
+
+
+ net10.0
+ false
+ enable
+ true
+ enable
+ false
+ true
+ $([System.IO.Path]::Combine($(MSBuildProjectDirectory),'..','..','StellaOps.Workflow.WebService','PluginBinaries','$(MSBuildProjectName)'))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ runtime
+
+
+ false
+ runtime
+
+
+ false
+ runtime
+
+
+
diff --git a/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Oracle/ServiceRegistrator.cs b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Oracle/ServiceRegistrator.cs
new file mode 100644
index 000000000..0e29b71ff
--- /dev/null
+++ b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Oracle/ServiceRegistrator.cs
@@ -0,0 +1,45 @@
+using StellaOps.DependencyInjection;
+using StellaOps.Workflow.Abstractions;
+using StellaOps.Workflow.DataStore.Oracle;
+using StellaOps.Workflow.Signaling.OracleAq;
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
+namespace StellaOps.Workflow.Plugin.WorkflowStore.Oracle;
+
+public sealed class ServiceRegistrator : IDependencyInjectionRoutine
+{
+ public IServiceCollection Register(IServiceCollection services, IConfiguration configuration)
+ {
+ services.AddWorkflowOracleDataStore(configuration);
+
+ if (!string.Equals(configuration.GetWorkflowBackendProvider(), WorkflowBackendNames.Oracle, StringComparison.OrdinalIgnoreCase))
+ {
+ return services;
+ }
+
+ var useNativeSignalDriver = string.Equals(
+ configuration.GetWorkflowSignalDriverProvider(),
+ WorkflowSignalDriverNames.Native,
+ StringComparison.OrdinalIgnoreCase);
+
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.Replace(ServiceDescriptor.Scoped(sp => sp.GetRequiredService()));
+ services.Replace(ServiceDescriptor.Scoped(sp => sp.GetRequiredService()));
+ services.Replace(ServiceDescriptor.Scoped(sp => sp.GetRequiredService()));
+ services.Replace(ServiceDescriptor.Scoped());
+ if (useNativeSignalDriver)
+ {
+ services.Replace(ServiceDescriptor.Scoped(sp => sp.GetRequiredService()));
+ }
+
+ services.AddSingleton(
+ new WorkflowSignalDriverRegistrationMarker(WorkflowSignalDriverNames.Native));
+
+ return services;
+ }
+}
diff --git a/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Oracle/StellaOps.Workflow.Plugin.WorkflowStore.Oracle.csproj b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Oracle/StellaOps.Workflow.Plugin.WorkflowStore.Oracle.csproj
new file mode 100644
index 000000000..4ae46bed2
--- /dev/null
+++ b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Oracle/StellaOps.Workflow.Plugin.WorkflowStore.Oracle.csproj
@@ -0,0 +1,45 @@
+
+
+ net10.0
+ false
+ enable
+ true
+ enable
+ false
+ true
+ $([System.IO.Path]::Combine($(MSBuildProjectDirectory),'..','..','StellaOps.Workflow.WebService','PluginBinaries','$(MSBuildProjectName)'))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ runtime
+
+
+ false
+ runtime
+
+
+ false
+ runtime
+
+
+ false
+ runtime
+
+
+ false
+ runtime
+
+
+
diff --git a/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Postgres/ServiceRegistrator.cs b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Postgres/ServiceRegistrator.cs
new file mode 100644
index 000000000..f852fc5b0
--- /dev/null
+++ b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Postgres/ServiceRegistrator.cs
@@ -0,0 +1,16 @@
+using StellaOps.DependencyInjection;
+using StellaOps.Workflow.Abstractions;
+using StellaOps.Workflow.DataStore.PostgreSQL;
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace StellaOps.Workflow.Plugin.WorkflowStore.Postgres;
+
+public sealed class ServiceRegistrator : IDependencyInjectionRoutine
+{
+ public IServiceCollection Register(IServiceCollection services, IConfiguration configuration)
+ {
+ return services.AddWorkflowPostgresDataStore(configuration);
+ }
+}
diff --git a/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Postgres/StellaOps.Workflow.Plugin.WorkflowStore.Postgres.csproj b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Postgres/StellaOps.Workflow.Plugin.WorkflowStore.Postgres.csproj
new file mode 100644
index 000000000..8810d0ddc
--- /dev/null
+++ b/src/Workflow/__Plugins/StellaOps.Workflow.Plugin.WorkflowStore.Postgres/StellaOps.Workflow.Plugin.WorkflowStore.Postgres.csproj
@@ -0,0 +1,37 @@
+
+
+ net10.0
+ false
+ enable
+ true
+ enable
+ false
+ true
+ $([System.IO.Path]::Combine($(MSBuildProjectDirectory),'..','..','StellaOps.Workflow.WebService','PluginBinaries','$(MSBuildProjectName)'))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ runtime
+
+
+ false
+ runtime
+
+
+ false
+ runtime
+
+
+