diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowDefinitionsContracts.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowDefinitionsContracts.cs
index a3d59ce14..a43d0846c 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowDefinitionsContracts.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowDefinitionsContracts.cs
@@ -33,6 +33,16 @@ public sealed record WorkflowDefinitionGetRequest
/// Pagination: max rows to return. 0 = return all.
public int Take { get; init; }
+ ///
+ /// Pagination (1-based) alternative that matches the sc-table-view payload convention.
+ /// When both are > 0 the server derives Skip = (Page - 1) * PageSize and
+ /// Take = PageSize, taking precedence over explicit Skip/Take.
+ ///
+ public int Page { get; init; }
+
+ /// See .
+ public int PageSize { get; init; }
+
///
/// Optional sort. SortBy is whitelisted per-endpoint — for definitions the allowed values are
/// "workflowName", "workflowVersion", "displayName". Null sorts by a stable default.
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowInstanceContracts.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowInstanceContracts.cs
index 97129b20e..8e00111cb 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowInstanceContracts.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowInstanceContracts.cs
@@ -47,6 +47,16 @@ public sealed record WorkflowInstancesGetRequest
/// Pagination: max rows to return. 0 = use server default cap.
public int Take { get; init; }
+ ///
+ /// Pagination (1-based) alternative that matches the sc-table-view payload convention.
+ /// When both are > 0 the server derives Skip = (Page - 1) * PageSize and
+ /// Take = PageSize, taking precedence over explicit Skip/Take.
+ ///
+ public int Page { get; init; }
+
+ /// See .
+ public int PageSize { get; init; }
+
///
/// Optional sort. SortBy is whitelisted per-endpoint — for instances the allowed values are
/// "workflowInstanceId", "workflowName", "workflowVersion", "status", "createdOnUtc",
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowOperationalContracts.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowOperationalContracts.cs
index 0e4f60698..62777e3f8 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowOperationalContracts.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowOperationalContracts.cs
@@ -91,6 +91,16 @@ public sealed record WorkflowSignalDeadLettersGetRequest
/// Pagination: max rows to return. 0 = use as the effective cap.
public int Take { get; init; }
+ ///
+ /// Pagination (1-based) alternative that matches the sc-table-view payload convention.
+ /// When both are > 0 the server derives Skip = (Page - 1) * PageSize and
+ /// Take = PageSize, taking precedence over explicit Skip/Take.
+ ///
+ public int Page { get; init; }
+
+ /// See .
+ public int PageSize { get; init; }
+
///
/// Optional sort. SortBy is whitelisted — allowed values are "signalId", "workflowInstanceId",
/// "signalType", "enqueuedOnUtc", "deliveryCount". Null sorts by enqueuedOnUtc desc.
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowTaskContracts.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowTaskContracts.cs
index a1b5ed9b4..14ef2419f 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowTaskContracts.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Contracts/WorkflowTaskContracts.cs
@@ -63,6 +63,16 @@ public sealed record WorkflowTasksGetRequest
/// Pagination: max rows to return. 0 = use server default cap.
public int Take { get; init; }
+ ///
+ /// Pagination (1-based) alternative that matches the sc-table-view payload convention.
+ /// When both are > 0 the server derives Skip = (Page - 1) * PageSize and
+ /// Take = PageSize, taking precedence over explicit Skip/Take.
+ ///
+ public int Page { get; init; }
+
+ /// See .
+ public int PageSize { get; init; }
+
///
/// Optional sort. SortBy is whitelisted per-endpoint — for tasks the allowed values are
/// "workflowTaskId", "taskName", "workflowName", "workflowVersion", "status", "assignee",
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.MongoDB/MongoWorkflowSignalStore.cs b/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.MongoDB/MongoWorkflowSignalStore.cs
index d6171c087..346b8ac51 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.MongoDB/MongoWorkflowSignalStore.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.MongoDB/MongoWorkflowSignalStore.cs
@@ -284,9 +284,9 @@ public sealed class MongoWorkflowSignalStore(
filter &= Builders.Filter.Eq(x => x.SignalType, request.SignalType);
}
- var effectiveTake = request.Take > 0 ? request.Take : request.MaxMessages;
- effectiveTake = Math.Clamp(effectiveTake, 1, 500);
- var effectiveSkip = Math.Max(0, request.Skip);
+ var (effectiveSkip, effectiveTake) = (request.Page > 0 && request.PageSize > 0)
+ ? (Math.Max(0, (request.Page - 1) * request.PageSize), Math.Clamp(request.PageSize, 1, 500))
+ : (Math.Max(0, request.Skip), Math.Clamp(request.Take > 0 ? request.Take : request.MaxMessages, 1, 500));
// Count for the response envelope so the UI can render "page X of Y".
var totalCount = (int)Math.Min(int.MaxValue,
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.PostgreSQL/PostgresWorkflowSignalStore.cs b/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.PostgreSQL/PostgresWorkflowSignalStore.cs
index 8dfa4a906..f95220272 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.PostgreSQL/PostgresWorkflowSignalStore.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.DataStore.PostgreSQL/PostgresWorkflowSignalStore.cs
@@ -308,11 +308,12 @@ public sealed class PostgresWorkflowSignalStore(
// Resolve an ORDER BY clause from the whitelist — never interpolate user input into SQL.
var orderBy = ResolveDeadLetterOrderBy(request.Sort);
- // Effective cap: use Take when given; otherwise MaxMessages. Hard-cap at 500 so a slow
- // driver can't be asked for an unbounded result set.
- var effectiveTake = request.Take > 0 ? request.Take : request.MaxMessages;
- effectiveTake = Math.Clamp(effectiveTake, 1, 500);
- var effectiveSkip = Math.Max(0, request.Skip);
+ // Effective cap. Precedence: Page/PageSize (sc-table-view) first, then Skip/Take, then
+ // MaxMessages as a safety cap. Hard-cap at 500 so a slow driver can't be asked for an
+ // unbounded result set.
+ var (effectiveSkip, effectiveTake) = (request.Page > 0 && request.PageSize > 0)
+ ? (Math.Max(0, (request.Page - 1) * request.PageSize), Math.Clamp(request.PageSize, 1, 500))
+ : (Math.Max(0, request.Skip), Math.Clamp(request.Take > 0 ? request.Take : request.MaxMessages, 1, 500));
await using var scope = await database.OpenScopeAsync(requireTransaction: false, cancellationToken);
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Engine/Projections/WorkflowProjectionStore.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Engine/Projections/WorkflowProjectionStore.cs
index 75f1719bf..7f5e02f31 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Engine/Projections/WorkflowProjectionStore.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Engine/Projections/WorkflowProjectionStore.cs
@@ -156,11 +156,11 @@ public sealed class WorkflowProjectionStore(
.ToArray();
}
- // Honour Skip/Take when the client asked for a page (0 means "all").
- if (request.Skip > 0 || request.Take > 0)
+ // Honour Page/PageSize (sc-table-view convention) first, falling back to Skip/Take.
+ var (skip, take) = ResolveSkipTake(request.Skip, request.Take, request.Page, request.PageSize, summaries.Length);
+ if (skip > 0 || take < summaries.Length)
{
- var take = request.Take > 0 ? request.Take : summaries.Length;
- summaries = summaries.Skip(request.Skip).Take(take).ToArray();
+ summaries = summaries.Skip(skip).Take(take).ToArray();
}
return summaries;
@@ -528,10 +528,10 @@ public sealed class WorkflowProjectionStore(
.Where(x => x.BusinessReference.MatchesBusinessReferenceFilter(businessReferenceKey, request.BusinessReferenceParts))
.ToArray();
- if (request.Skip > 0 || request.Take > 0)
+ var (iSkip, iTake) = ResolveSkipTake(request.Skip, request.Take, request.Page, request.PageSize, filtered.Length);
+ if (iSkip > 0 || iTake < filtered.Length)
{
- var take = request.Take > 0 ? request.Take : filtered.Length;
- filtered = filtered.Skip(request.Skip).Take(take).ToArray();
+ filtered = filtered.Skip(iSkip).Take(iTake).ToArray();
}
return filtered;
@@ -770,6 +770,21 @@ public sealed class WorkflowProjectionStore(
return JsonSerializer.Serialize(value, SerializerOptions);
}
+ ///
+ /// Resolves the effective (skip, take) pair from the request. Page/PageSize
+ /// (sc-table-view convention, 1-based) take precedence over explicit Skip/Take when provided.
+ ///
+ private static (int Skip, int Take) ResolveSkipTake(int requestSkip, int requestTake, int requestPage, int requestPageSize, int totalLength)
+ {
+ if (requestPage > 0 && requestPageSize > 0)
+ {
+ return (Math.Max(0, (requestPage - 1) * requestPageSize), requestPageSize);
+ }
+
+ var take = requestTake > 0 ? requestTake : totalLength;
+ return (Math.Max(0, requestSkip), take);
+ }
+
private static string? SerializeBusinessReference(WorkflowBusinessReference? businessReference)
{
var normalizedReference = WorkflowBusinessReferenceExtensions.NormalizeBusinessReference(businessReference);
diff --git a/src/Workflow/__Libraries/StellaOps.Workflow.Signaling.OracleAq/OracleAqWorkflowSignalDeadLetterStore.cs b/src/Workflow/__Libraries/StellaOps.Workflow.Signaling.OracleAq/OracleAqWorkflowSignalDeadLetterStore.cs
index e40ab4ac0..b49b47c6c 100644
--- a/src/Workflow/__Libraries/StellaOps.Workflow.Signaling.OracleAq/OracleAqWorkflowSignalDeadLetterStore.cs
+++ b/src/Workflow/__Libraries/StellaOps.Workflow.Signaling.OracleAq/OracleAqWorkflowSignalDeadLetterStore.cs
@@ -55,9 +55,10 @@ public sealed class OracleAqWorkflowSignalDeadLetterStore(
var sorted = ApplyInMemorySort(filtered, request.Sort);
var totalCount = sorted.Count;
- var effectiveTake = request.Take > 0 ? request.Take : safetyCap;
- effectiveTake = Math.Clamp(effectiveTake, 1, 500);
- var effectiveSkip = Math.Max(0, request.Skip);
+ // Page/PageSize (sc-table-view) first, then Skip/Take, then safetyCap fallback.
+ var (effectiveSkip, effectiveTake) = (request.Page > 0 && request.PageSize > 0)
+ ? (Math.Max(0, (request.Page - 1) * request.PageSize), Math.Clamp(request.PageSize, 1, 500))
+ : (Math.Max(0, request.Skip), Math.Clamp(request.Take > 0 ? request.Take : safetyCap, 1, 500));
var page = sorted.Skip(effectiveSkip).Take(effectiveTake).ToArray();
return new WorkflowSignalDeadLettersGetResponse