Skip to content

Migrate dashboard endpoints to Immediate.Apis - #84

Merged
viceroypenguin merged 3 commits into
mainfrom
feature/dashboard-immediate-apis-validations
Jul 31, 2026
Merged

Migrate dashboard endpoints to Immediate.Apis#84
viceroypenguin merged 3 commits into
mainfrom
feature/dashboard-immediate-apis-validations

Conversation

@dukesteen

@dukesteen dukesteen commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Stack

Summary

  • replace hand-mapped monitoring APIs with Immediate.Apis-generated handlers under the existing dashboard route group
  • validate route and paging inputs with Immediate.Validations and return structured validation problem details
  • add AddImmediateJobsDashboard registration while preserving the existing prefix, authorization, SPA, JSON, and SSE behavior
  • update samples and documentation for service registration

Verification

  • dotnet build Immediate.Jobs.slnx -c Release -p:TreatWarningsAsErrors=true -v:minimal
  • dotnet test tests/Immediate.Jobs.FunctionalTests/Immediate.Jobs.FunctionalTests.csproj -c Release --no-restore -p:TreatWarningsAsErrors=true -v:minimal (748 passed across net8.0, net9.0, net10.0, and net11.0)
  • dotnet pack src/Immediate.Jobs.Dashboard/Immediate.Jobs.Dashboard.csproj -c Release --no-build
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Added a Jobs dashboard with APIs for monitoring jobs, executions, batches, recurring jobs, servers, telemetry, and live event updates.
    • Added configurable dashboard registration, endpoint mapping, and optional telemetry links.
    • Added standard JSON Problem Details responses for validation errors.
  • Bug Fixes

    • Invalid routes and paging values now return clear 400 Bad Request responses.
    • Dashboard configuration rejects invalid update intervals.
  • Documentation

    • Updated dashboard setup instructions and API behavior documentation.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b0fa6c0-36fb-4a74-9f1a-c86bd4eb858b

📥 Commits

Reviewing files that changed from the base of the PR and between 1dd4b19 and 1252994.

📒 Files selected for processing (1)
  • coverage-settings.xml
🚧 Files skipped from review as they are similar to previous changes (1)
  • coverage-settings.xml

📝 Walkthrough

Walkthrough

The dashboard now registers services before application build and maps generated API endpoints afterward. It adds typed dashboard routes, validation problem details, mutation handling, telemetry links, and dashboard and batch SSE streams.

Changes

Dashboard API

Layer / File(s) Summary
Registration and API wiring
Directory.Packages.props, src/Immediate.Jobs.Dashboard/..., docs/..., readme.md, samples/..., coverage-settings.xml
Dashboard services, options, validation, package references, documentation, samples, and coverage settings now support service registration before endpoint mapping.
Dashboard API endpoints
src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs
Adds typed overview, job, execution, batch, recurring-job, server, telemetry, and mutation endpoints with validation and storage checks.
Dashboard streaming
src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs
Adds dashboard-wide and batch SSE streams with periodic state updates, change detection, flushing, and cancellation handling.
Functional validation
tests/Immediate.Jobs.FunctionalTests/...
Updates dashboard setup and verifies invalid paging values as application/problem+json validation responses.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant DashboardApiEndpoints
  participant IJobStorage
  participant JobMutations
  Client->>DashboardApiEndpoints: Send dashboard request
  DashboardApiEndpoints->>IJobStorage: Query dashboard data
  DashboardApiEndpoints->>JobMutations: Apply requested mutation
  IJobStorage-->>DashboardApiEndpoints: Return data or missing-resource result
  JobMutations-->>DashboardApiEndpoints: Return mutation result
  DashboardApiEndpoints-->>Client: Return typed response or problem details
Loading

Possibly related PRs

Suggested reviewers: viceroypenguin

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: migrating dashboard endpoints to Immediate.Apis.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/dashboard-immediate-apis-validations

Comment @coderabbitai help to get the list of available commands.

@dukesteen
dukesteen force-pushed the feature/job-retention branch from 2996c18 to 4c06ba3 Compare July 31, 2026 18:28
@dukesteen
dukesteen force-pushed the feature/dashboard-immediate-apis-validations branch from dcbb6ab to 5e6c14c Compare July 31, 2026 18:36
@coveralls

coveralls commented Jul 31, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 30663166872

Coverage decreased (-0.3%) to 83.799%

Details

  • Coverage decreased (-0.3%) from the base build.
  • Patch coverage: 143 uncovered changes across 2 files (193 of 336 lines covered, 57.44%).
  • 1 coverage regression across 1 file.

Uncovered Changes

File Changed Covered %
src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs 306 164 53.59%
src/Immediate.Jobs.Dashboard/ImmediateJobsDashboardOptions.cs 3 2 66.67%
Total (5 files) 336 193 57.44%

Coverage Regressions

1 previously-covered line in 1 file lost coverage.

File Lines Losing Coverage Coverage
src/Immediate.Jobs.Shared/JobSchedulerService.cs 1 90.48%

Coverage Stats

Coverage Status
Relevant Lines: 9666
Covered Lines: 8100
Line Coverage: 83.8%
Coverage Strength: 2.71 hits per line

💛 - Coveralls

@dukesteen
dukesteen force-pushed the feature/dashboard-immediate-apis-validations branch from 5e6c14c to ce6f738 Compare July 31, 2026 18:45
Base automatically changed from feature/job-retention to main July 31, 2026 19:08
@viceroypenguin
viceroypenguin force-pushed the feature/dashboard-immediate-apis-validations branch from ce6f738 to ce641c2 Compare July 31, 2026 19:17
viceroypenguin
viceroypenguin previously approved these changes Jul 31, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/Immediate.Jobs.Dashboard/ImmediateJobsDashboardServiceCollectionExtensions.cs (1)

19-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the options registration idempotent.

AddSingleton(options) appends a new registration on every call. If an application calls AddImmediateJobsDashboard twice, for example once in a shared extension and once in Program.cs, the last registration wins and every telemetry link and authorization policy configured by the first call is discarded silently. Use TryAddSingleton and apply configure to the already-registered instance, or throw on a second registration.

♻️ Proposed change
-		var options = new ImmediateJobsDashboardOptions();
-		configure?.Invoke(options);
-		options.Validate();
-
-		_ = services.AddSingleton(options);
+		var options = (ImmediateJobsDashboardOptions?)services
+			.FirstOrDefault(d => d.ServiceType == typeof(ImmediateJobsDashboardOptions))?.ImplementationInstance
+			?? new ImmediateJobsDashboardOptions();
+		configure?.Invoke(options);
+		options.Validate();
+
+		services.TryAddSingleton(options);

This requires using Microsoft.Extensions.DependencyInjection.Extensions;.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/Immediate.Jobs.Dashboard/ImmediateJobsDashboardServiceCollectionExtensions.cs`
around lines 19 - 27, Make options registration idempotent in
AddImmediateJobsDashboard by using TryAddSingleton with the existing options
instance and importing Microsoft.Extensions.DependencyInjection.Extensions;
ensure repeated calls preserve the initially registered configuration rather
than silently replacing it.
src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs (2)

703-716: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

MutateJobAsync and MutateBatchAsync are identical.

Both delegate to MutateAsync(operation, includeConflict: true). Two names for one behavior invite divergence later. Keep MutateRecurringAsync and replace the other two with a single MutateAsync(operation, includeConflict: true) call at each site, or expose one method with the flag.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs` around lines 703 -
716, Remove the redundant MutateJobAsync and MutateBatchAsync wrappers, and
update their callers to invoke MutateAsync with includeConflict: true directly.
Preserve MutateRecurringAsync with includeConflict: false and retain the
existing behavior at each call site.

758-777: 🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy lift

Consider the storage cost of the dashboard SSE loop.

Each connected client polls independently. Every iteration issues one monitoring snapshot query, one 100-row job query, and one 100-row batch query. At the default 2-second UpdateInterval, ten open dashboard tabs generate about fifteen storage queries per second against the jobs database. Consider a shared background snapshot that all SSE connections read, or a per-process cache keyed by interval, so the query rate stays independent of client count.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs` around lines 758 -
777, Reduce storage load in the dashboard SSE loop around
GetMonitoringSnapshotAsync, QueryJobsAsync, and QueryBatchesAsync by introducing
a shared background snapshot or per-process cache keyed by the update interval.
Have each connected client read the cached DashboardState instead of issuing
storage queries independently, while preserving the existing SSE serialization,
event format, flushing, cancellation, and interval behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs`:
- Around line 409-414: Add [FromRoute] to the BatchId property in
DeleteDashboardBatch.Command and the JobId property in
DeleteDashboardJob.Command, alongside their existing [NotEmpty] attributes, so
DELETE route values bind correctly; also add functional coverage for DELETE
/api/batches/{id} and DELETE /api/jobs/{id}.

In
`@src/Immediate.Jobs.Dashboard/ImmediateJobsDashboardEndpointRouteBuilderExtensions.cs`:
- Around line 45-46: Prevent map-time configuration from mutating the shared
options singleton in the endpoint route-mapping flow around
configure?.Invoke(options) and options.Validate(). Prefer cloning the registered
options for each mapped dashboard group before applying configure and
validating, so repeated mappings do not duplicate telemetry links and active
requests retain their original settings.

---

Nitpick comments:
In `@src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs`:
- Around line 703-716: Remove the redundant MutateJobAsync and MutateBatchAsync
wrappers, and update their callers to invoke MutateAsync with includeConflict:
true directly. Preserve MutateRecurringAsync with includeConflict: false and
retain the existing behavior at each call site.
- Around line 758-777: Reduce storage load in the dashboard SSE loop around
GetMonitoringSnapshotAsync, QueryJobsAsync, and QueryBatchesAsync by introducing
a shared background snapshot or per-process cache keyed by the update interval.
Have each connected client read the cached DashboardState instead of issuing
storage queries independently, while preserving the existing SSE serialization,
event format, flushing, cancellation, and interval behavior.

In
`@src/Immediate.Jobs.Dashboard/ImmediateJobsDashboardServiceCollectionExtensions.cs`:
- Around line 19-27: Make options registration idempotent in
AddImmediateJobsDashboard by using TryAddSingleton with the existing options
instance and importing Microsoft.Extensions.DependencyInjection.Extensions;
ensure repeated calls preserve the initially registered configuration rather
than silently replacing it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3ba8eaeb-f7d1-494c-a671-84ef26bcd2ff

📥 Commits

Reviewing files that changed from the base of the PR and between cdd3172 and ce641c2.

📒 Files selected for processing (13)
  • Directory.Packages.props
  • docs/monitoring-api.md
  • readme.md
  • samples/Aspire/Api/Program.cs
  • samples/Basic/Program.cs
  • src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs
  • src/Immediate.Jobs.Dashboard/DashboardValidationFilter.cs
  • src/Immediate.Jobs.Dashboard/Immediate.Jobs.Dashboard.csproj
  • src/Immediate.Jobs.Dashboard/ImmediateJobsDashboardEndpointRouteBuilderExtensions.cs
  • src/Immediate.Jobs.Dashboard/ImmediateJobsDashboardOptions.cs
  • src/Immediate.Jobs.Dashboard/ImmediateJobsDashboardServiceCollectionExtensions.cs
  • tests/Immediate.Jobs.FunctionalTests/GeneratedJobTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Packages/DashboardPackageTests.cs

Comment on lines +409 to +414
[Validate]
internal sealed partial record Command : IValidationTarget<Command>
{
[NotEmpty]
public required string BatchId { get; init; }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Both DELETE commands omit [FromRoute] on their route property. Every other mutation command in this file declares [FromRoute] (lines 388, 477, 520, 574, 598). For non-GET routes, Immediate.Apis binds the request record from the request body unless a member declares its binding source, and a DELETE request carries no body, so the route value never reaches the command.

  • src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs#L409-L414: add [FromRoute] above [NotEmpty] on DeleteDashboardBatch.Command.BatchId.
  • src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs#L496-L501: add [FromRoute] above [NotEmpty] on DeleteDashboardJob.Command.JobId.

Add functional test coverage for DELETE /api/jobs/{id} and DELETE /api/batches/{id}, because both paths are currently uncovered according to the reported patch coverage.

📍 Affects 1 file
  • src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs#L409-L414 (this comment)
  • src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs#L496-L501
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Immediate.Jobs.Dashboard/DashboardApiEndpoints.cs` around lines 409 -
414, Add [FromRoute] to the BatchId property in DeleteDashboardBatch.Command and
the JobId property in DeleteDashboardJob.Command, alongside their existing
[NotEmpty] attributes, so DELETE route values bind correctly; also add
functional coverage for DELETE /api/batches/{id} and DELETE /api/jobs/{id}.

Comment on lines 45 to +46
configure?.Invoke(options);
if (options.UpdateInterval <= TimeSpan.Zero)
throw new ArgumentOutOfRangeException(nameof(configure), "The dashboard update interval must be positive.");
options.Validate();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Map-time configure mutates the shared options singleton.

options is the singleton instance registered by AddImmediateJobsDashboard. This call mutates it after the container is built. Two consequences follow:

  • If an application maps the dashboard at two prefixes, AddTelemetryLink appends the same links again, so every job-detail page shows duplicated links.
  • The mutation is visible to any request already resolving the singleton, including active SSE streams that read options.UpdateInterval.

Consider treating the map-time configure as deprecated and directing configuration to AddImmediateJobsDashboard, or clone the options instance for the group being mapped.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/Immediate.Jobs.Dashboard/ImmediateJobsDashboardEndpointRouteBuilderExtensions.cs`
around lines 45 - 46, Prevent map-time configuration from mutating the shared
options singleton in the endpoint route-mapping flow around
configure?.Invoke(options) and options.Validate(). Prefer cloning the registered
options for each mapped dashboard group before applying configure and
validating, so repeated mappings do not duplicate telemetry links and active
requests retain their original settings.

@viceroypenguin
viceroypenguin merged commit c8caa3f into main Jul 31, 2026
2 of 4 checks passed
@viceroypenguin
viceroypenguin deleted the feature/dashboard-immediate-apis-validations branch July 31, 2026 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants