AutoMate Technisch Help

Klant Statistieken — Techniek (Backend)

Deze pagina beschrijft de back-end implementatie van Tenant Metrics, met concrete codevoorbeelden uit de repository.

Overzicht

  • Scheduler: Hangfire recurring jobs (iam-metrics-daily en iam-metrics-monthly)

  • Job class: IamMetricsJobs

  • Command: CreateTenantMetricsRequest

  • Handler: CreateTenantMetricsHandler

  • Repository: IMetricsRepository/TenantMetricRepository

  • Events: TenantMetricsCreatedEvent, TenantMetricsFailedEvent

Hangfire Jobs (Scheduler)

De metrics worden gegenereerd via twee Hangfire recurring jobs, geregistreerd in Program.cs:

// Dagelijkse metrics om 01:00 UTC recurring.AddOrUpdate<IamMetricsJobs>( recurringJobId: "iam-metrics-daily", methodCall: x => x.RunGenerateIamMetricsDailyAsync(CancellationToken.None), cronExpression: "0 1 * * *", recurringJobOptions); // Maandelijkse metrics op de 1e van de maand om 05:00 UTC recurring.AddOrUpdate<IamMetricsJobs>( recurringJobId: "iam-metrics-monthly", methodCall: x => x.RunGenerateIamMetricsMonthlyAsync(CancellationToken.None), cronExpression: "0 5 1 * *", recurringJobOptions);
  • iam-metrics-daily — draait elke dag om 01:00 UTC en genereert dagelijkse KPI's per tenant.

  • iam-metrics-monthly — draait op de 1e van elke maand om 05:00 UTC en genereert maandelijkse statistieken.

Beide jobs roepen methoden aan op de IamMetricsJobs class, die intern de CreateTenantMetricsRequest verzendt via MediatR.

Command & Handler

Bronnen:

  • .../Tenant/Metrics/Create/CreateTenantMetricsRequest.cs

  • .../Tenant/Metrics/Create/CreateTenantMetricsHandler.cs

Belangrijkste logica uit de handler:

public async ValueTask<CreateTenantMetricsResponse> Handle(CreateTenantMetricsRequest request, CancellationToken ct) { var tenants = await sender.Send(new GetTenantListQuery(), ct); List<TenantMetric> tenantMetrics = []; foreach (var tenantId in tenants.Tenants) { multiTenantService.SetTenantId(tenantId); var currentTenant = await tenantRepository.GetAsync(tenantId, ct); var users = await sender.Send(new EmployeeGetAllQuery(), ct); var payload = new Dictionary<string, object> { { "TotalUsers", users.Count } }; var metric = TenantMetric.Create(payload); metric.SetTenant(currentTenant); tenantMetrics.Add(metric); } var response = new CreateTenantMetricsResponse(tenantMetrics); if (!request.SaveToDatabase) return response; await tenantMetricRepository.CreateMetrics(tenantMetrics, ct); await unitOfWork.SaveChangesAsync(ct); return response; }
  • Haalt de tenantlijst op, stelt per tenant de multi-tenant context in, telt medewerkers en bouwt de metric.

  • Slaat alleen op als SaveToDatabase waar is (standaard bij de Hangfire jobs).

Domein Entiteit

Bron: .../Domain/Entities/Metrics/TenantMetric.cs

public class TenantMetric : AggregateRoot<Guid> { public Tenant Tenant { get; set; } public Dictionary<string, object> Payload { get; set; } public static TenantMetric Create(Dictionary<string, object> payload) => new(payload); public void SetTenant(Tenant tenant) => Tenant = tenant; }

De flexibele Payload maakt het eenvoudig om nieuwe KPI's toe te voegen zonder schemawijziging.

Voorbeeld payload

{ "TotalUsers": 128 }

Repositories

Bron: .../Infrastructure/Repositories/TenantMetricRepository.cs

public async Task CreateMetrics(List<TenantMetric> tenantMetrics, CancellationToken ct) => await context.TenantMetrics.AddRangeAsync(tenantMetrics, ct); public async Task<List<TenantMetric>> GetMetrics(CancellationToken ct) => await context.TenantMetrics.ToListAsync(ct); public async Task<List<TenantMetric>> GetMetrics(int month, CancellationToken ct) => await context.TenantMetrics .IgnoreQueryFilters() .Where(m => m.CreatedAt.Month == month) .Include(m => m.Tenant) .ToListAsync(ct);

GetMetrics(month) wordt gebruikt voor rapportages met maandfiltering en laadt de gekoppelde tenant mee.

Idempotentie en datakwaliteit

Overweeg een check vóór opslag om dubbele metrics te voorkomen:

// Bestaat er al een metric voor (tenantId, jaar, maand)? var exists = await context.TenantMetrics.AnyAsync( m => m.Tenant.Id == tenantId && m.CreatedAt.Year == now.Year && m.CreatedAt.Month == now.Month, ct); if (!exists) { await repo.CreateMetric(metric, ct); }

Multi-tenant waarborgen

Per tenant wordt IMultiTenantService.SetTenantId(tenantId) aangeroepen vóórdat data wordt gelezen of geschreven. Repositories werken daarmee impliciet in de juiste tenantcontext.

Uitbreiden van metrieken

Extra KPI's toevoegen in de handler:

var activeUsers = users.Count(u => u.IsActive); payload["ActiveUsers"] = activeUsers;

De front-end kan deze vervolgens uitlezen zonder schemawijziging.

Last modified: 24 March 2026