Add stat card sparkline graphs with timeseries backend endpoint
All checks were successful
CI / build (push) Successful in 1m0s
CI / docker (push) Successful in 45s
CI / deploy (push) Successful in 23s

New /search/stats/timeseries endpoint returns bucketed counts/metrics
over a time window using ClickHouse toStartOfInterval(). Frontend
Sparkline component renders SVG polyline + gradient fill on each
stat card, driven by a useStatsTimeseries query hook.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-13 18:20:08 +01:00
parent cccd3f07be
commit 9e6e1b350a
10 changed files with 217 additions and 7 deletions

View File

@@ -31,4 +31,14 @@ public interface SearchEngine {
* @return execution stats
*/
ExecutionStats stats();
/**
* Compute bucketed time-series stats over a time window.
*
* @param from start of the time window
* @param to end of the time window
* @param bucketCount number of buckets to divide the window into
* @return bucketed stats
*/
StatsTimeseries timeseries(java.time.Instant from, java.time.Instant to, int bucketCount);
}

View File

@@ -35,4 +35,11 @@ public class SearchService {
public ExecutionStats stats() {
return engine.stats();
}
/**
* Compute bucketed time-series stats over a time window.
*/
public StatsTimeseries timeseries(java.time.Instant from, java.time.Instant to, int bucketCount) {
return engine.timeseries(from, to, bucketCount);
}
}

View File

@@ -0,0 +1,17 @@
package com.cameleer3.server.core.search;
import java.time.Instant;
import java.util.List;
public record StatsTimeseries(
List<TimeseriesBucket> buckets
) {
public record TimeseriesBucket(
Instant time,
long totalCount,
long failedCount,
long avgDurationMs,
long p99DurationMs,
long activeCount
) {}
}