2989a6fa2c
First Wave 2 (safe refactor) slice. Move the read-only stats/overview aggregation out of the 3.3k-line JobApplicationsController into a dedicated, injectable AnalyticsService, and lift its response DTOs (JobStats, FunnelStagePoint, ResponseRatePoint, CompanyActivityPoint, AnalyticsOverviewDto) into Models/AnalyticsDtos.cs. - GetStats: ~44 lines -> 3 (delegates to AnalyticsService.GetStatsAsync). - GetAnalyticsOverview: ~82 lines -> 3 (delegates to GetAnalyticsOverviewAsync). - Registered AddScoped<AnalyticsService>(); controller keeps an optional ctor param with a `?? new AnalyticsService(db)` fallback so the 6 test sites that construct the controller directly keep compiling. - Logic is byte-identical (same tenant-scoped context, same projections) so behaviour is preserved. Backend suite: 92/92 green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
31 lines
1.0 KiB
C#
31 lines
1.0 KiB
C#
using System.Collections.Generic;
|
|
|
|
namespace JobTrackerApi.Models
|
|
{
|
|
// Read-only analytics/statistics response DTOs. Extracted from
|
|
// JobApplicationsController so the aggregation logic can live in AnalyticsService.
|
|
public sealed record JobStats(
|
|
int Total,
|
|
int Active,
|
|
int Deleted,
|
|
Dictionary<string, int> ByStatus,
|
|
int AppliedLast30Days,
|
|
double AverageDaysSinceApplied
|
|
);
|
|
|
|
public sealed record FunnelStagePoint(string Label, int Count);
|
|
|
|
public sealed record ResponseRatePoint(string Label, int Total, int Responses, double Rate);
|
|
|
|
public sealed record CompanyActivityPoint(int CompanyId, string Company, int Count, int Responses, double ResponseRate);
|
|
|
|
public sealed record AnalyticsOverviewDto(
|
|
List<FunnelStagePoint> Funnel,
|
|
List<ResponseRatePoint> ResponseRateBySource,
|
|
List<CompanyActivityPoint> TopCompanies,
|
|
double? MedianDaysToFirstResponse,
|
|
int TotalResponses,
|
|
int TotalActive
|
|
);
|
|
}
|