Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new authenticated /api/stats endpoint intended for dashboard integrations by aggregating event/strike/job-run statistics and exposing cached health status for download clients and arr instances.
Changes:
- Introduces
StatsService+ response DTOs and wires them into DI. - Adds
StatsController(GET /api/stats?hours=...) and removes the old/api/events/statsendpoint. - Extends health checking to include arr instances and updates docs for the new stats API.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| docs/docs/configuration/stats/index.mdx | New documentation page describing auth, query params, and response fields for /api/stats. |
| code/backend/Cleanuparr.Infrastructure/Stats/StatsService.cs | Aggregates stats from Events DB + job scheduler + cached health service. |
| code/backend/Cleanuparr.Infrastructure/Stats/StatsResponse.cs | Adds the stats response contract/DTOs returned by the API. |
| code/backend/Cleanuparr.Infrastructure/Stats/IStatsService.cs | Defines the stats aggregation interface. |
| code/backend/Cleanuparr.Infrastructure/Health/IHealthCheckService.cs | Extends health service contract to support arr instance health checks. |
| code/backend/Cleanuparr.Infrastructure/Health/HealthCheckService.cs | Implements arr instance health checks and caching. |
| code/backend/Cleanuparr.Infrastructure/Health/HealthCheckBackgroundService.cs | Periodically checks both download clients and arr instances. |
| code/backend/Cleanuparr.Infrastructure/Health/ArrHealthStatus.cs | Adds arr instance health status model. |
| code/backend/Cleanuparr.Api/DependencyInjection/ServicesDI.cs | Registers IStatsService in API DI. |
| code/backend/Cleanuparr.Api/Controllers/StatsController.cs | New /api/stats controller endpoint with clamped hours. |
| code/backend/Cleanuparr.Api/Controllers/EventsController.cs | Removes the legacy /api/events/stats endpoint. |
Comments suppressed due to low confidence (5)
code/backend/Cleanuparr.Api/Controllers/EventsController.cs:156
- The
/api/events/statsendpoint was removed here, but the Angular frontend still calls it (code/frontend/src/app/core/api/events.api.ts#getEventStats). This will break the UI at runtime unless the frontend is updated in the same PR, or this endpoint is kept for backward compatibility (e.g., reintroduce it and have it delegate to the new stats service / return the previously expected shape).
/// <summary>
/// Manually triggers cleanup of old events
/// </summary>
[HttpPost("cleanup")]
public async Task<ActionResult<object>> CleanupOldEvents([FromQuery] int retentionDays = 30)
code/backend/Cleanuparr.Infrastructure/Health/HealthCheckService.cs:216
- In
CheckArrInstanceHealthAsync, the exception path returns anArrHealthStatuswith onlyInstanceIdpopulated;InstanceNameandInstanceTypewill be empty/default. That makes downstream consumers (like/api/statswhich serializesTypeviaInstanceType.ToString()) misleading when a check fails. Consider capturing the instance/config info before the health check call and populatingInstanceName/InstanceTypeeven on error.
catch (Exception ex)
{
_logger.LogError(ex, "Error performing health check for arr instance {instanceId}", instanceId);
var status = new ArrHealthStatus
{
InstanceId = instanceId,
IsHealthy = false,
LastChecked = DateTime.UtcNow,
ErrorMessage = $"Error: {ex.Message}"
};
UpdateArrHealthStatus(status);
return status;
docs/docs/configuration/stats/index.mdx:99
- The API response includes a top-level
generatedAtfield (seeStatsResponse.GeneratedAt), but the documentation only describes theevents/strikes/jobs/healthsections. Please documentgeneratedAt(and ideally show an example of the full top-level response shape) or remove the field if it isn’t intended to be part of the contract.
<SectionTitle icon="📋">Response Reference</SectionTitle>
<ConfigSection
title="events"
icon="📝"
>
docs/docs/configuration/stats/index.mdx:70
- The controller clamps
hoursto 1–720 (Math.Clamp(hours, 1, 720)), so out-of-range values won’t error but will be silently adjusted. The docs currently state a range, but don’t mention the clamping behavior; consider clarifying this to avoid confusing dashboard integrations that accidentally send e.g.hours=0orhours=999.
**Query Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `hours` | integer | `24` | Timeframe in hours (range: 1–720) |
code/backend/Cleanuparr.Api/Controllers/StatsController.cs:36
- There are no automated tests added for the new stats aggregation behavior (e.g., timeframe filtering, job
NextRunAtenrichment, and health serialization). Given the endpoint is intended for external dashboard polling, please add coverage (unit tests forStatsServiceand/or an API test forGET /api/stats).
/// <summary>
/// Gets aggregated application statistics for the specified timeframe
/// </summary>
/// <param name="hours">Timeframe in hours (default 24, range 1-720)</param>
[HttpGet]
public async Task<IActionResult> GetStats([FromQuery] int hours = 24)
{
try
{
hours = Math.Clamp(hours, 1, 720);
var stats = await _statsService.GetStatsAsync(hours);
return Ok(stats);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
code/backend/Cleanuparr.Infrastructure/Health/HealthCheckBackgroundService.cs
Show resolved
Hide resolved
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Relates to #250