Add StellaOps.Workflow engine: 14 libraries, WebService, 8 test projects

Extract product-agnostic workflow engine from Ablera.Serdica.Workflow into
standalone StellaOps.Workflow.* libraries targeting net10.0.

Libraries (14):
- Contracts, Abstractions (compiler, decompiler, expression runtime)
- Engine (execution, signaling, scheduling, projections, hosted services)
- ElkSharp (generic graph layout algorithm)
- Renderer.ElkSharp, Renderer.ElkJs, Renderer.Msagl, Renderer.Svg
- Signaling.Redis, Signaling.OracleAq
- DataStore.MongoDB, DataStore.PostgreSQL, DataStore.Oracle

WebService: ASP.NET Core Minimal API with 22 endpoints

Tests (8 projects, 109 tests pass):
- Engine.Tests (105 pass), WebService.Tests (4 E2E pass)
- Renderer.Tests, DataStore.MongoDB/Oracle/PostgreSQL.Tests
- Signaling.Redis.Tests, IntegrationTests.Shared

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-03-20 19:14:44 +02:00
parent e56f9a114a
commit f5b5f24d95
422 changed files with 85428 additions and 0 deletions

View File

@@ -0,0 +1,138 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace StellaOps.ElkSharp;
public enum ElkLayoutDirection
{
TopToBottom = 0,
LeftToRight = 1,
}
public enum ElkLayoutEffort
{
Draft = 0,
Balanced = 1,
Best = 2,
}
public sealed record ElkPort
{
public required string Id { get; init; }
public string? Side { get; init; }
public double Width { get; init; } = 8;
public double Height { get; init; } = 8;
}
public sealed record ElkNode
{
public required string Id { get; init; }
public required string Label { get; init; }
public required string Kind { get; init; }
public string? IconKey { get; init; }
public string? SemanticType { get; init; }
public string? SemanticKey { get; init; }
public string? Route { get; init; }
public string? TaskType { get; init; }
public string? ParentNodeId { get; init; }
public double Width { get; init; } = 160;
public double Height { get; init; } = 72;
public IReadOnlyCollection<ElkPort> Ports { get; init; } = [];
}
public sealed record ElkEdge
{
public required string Id { get; init; }
public required string SourceNodeId { get; init; }
public required string TargetNodeId { get; init; }
public string? SourcePortId { get; init; }
public string? TargetPortId { get; init; }
public string? Kind { get; init; }
public string? Label { get; init; }
}
public sealed record ElkGraph
{
public required string Id { get; init; }
public required IReadOnlyCollection<ElkNode> Nodes { get; init; }
public required IReadOnlyCollection<ElkEdge> Edges { get; init; }
}
public sealed record ElkLayoutOptions
{
public ElkLayoutDirection Direction { get; init; } = ElkLayoutDirection.LeftToRight;
public double NodeSpacing { get; init; } = 40;
public double LayerSpacing { get; init; } = 60;
public ElkLayoutEffort Effort { get; init; } = ElkLayoutEffort.Best;
public int? OrderingIterations { get; init; }
public int? PlacementIterations { get; init; }
}
public sealed record ElkPoint
{
public required double X { get; init; }
public required double Y { get; init; }
}
public sealed record ElkPositionedPort
{
public required string Id { get; init; }
public string? Side { get; init; }
public double X { get; init; }
public double Y { get; init; }
public double Width { get; init; }
public double Height { get; init; }
}
public sealed record ElkPositionedNode
{
public required string Id { get; init; }
public required string Label { get; init; }
public required string Kind { get; init; }
public string? IconKey { get; init; }
public string? SemanticType { get; init; }
public string? SemanticKey { get; init; }
public string? Route { get; init; }
public string? TaskType { get; init; }
public string? ParentNodeId { get; init; }
public double X { get; init; }
public double Y { get; init; }
public double Width { get; init; }
public double Height { get; init; }
public IReadOnlyCollection<ElkPositionedPort> Ports { get; init; } = [];
}
public sealed record ElkEdgeSection
{
public required ElkPoint StartPoint { get; init; }
public required ElkPoint EndPoint { get; init; }
public IReadOnlyCollection<ElkPoint> BendPoints { get; init; } = [];
}
public sealed record ElkRoutedEdge
{
public required string Id { get; init; }
public required string SourceNodeId { get; init; }
public required string TargetNodeId { get; init; }
public string? SourcePortId { get; init; }
public string? TargetPortId { get; init; }
public string? Kind { get; init; }
public string? Label { get; init; }
public IReadOnlyCollection<ElkEdgeSection> Sections { get; init; } = [];
}
public sealed record ElkLayoutResult
{
public required string GraphId { get; init; }
public required IReadOnlyCollection<ElkPositionedNode> Nodes { get; init; }
public required IReadOnlyCollection<ElkRoutedEdge> Edges { get; init; }
}
public interface IElkLayoutEngine
{
Task<ElkLayoutResult> LayoutAsync(
ElkGraph graph,
ElkLayoutOptions? options = null,
CancellationToken cancellationToken = default);
}