feat: add charts, world map, and filters to web dashboard
Add Chart.js line/bar charts for attack trends (attempts over time, hourly pattern), an SVG world map choropleth colored by attack origin country, and a collapsible filter form (date range, IP, country, username) that narrows both charts and top-N tables. New store methods: GetAttemptsOverTime, GetHourlyPattern, GetCountryStats, and filtered variants of dashboard stats/top-N queries. New JSON API endpoints at /api/charts/* and an htmx fragment at /fragments/dashboard-content for filtered table updates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,33 @@ type DashboardStats struct {
|
||||
ActiveSessions int64
|
||||
}
|
||||
|
||||
// TimeSeriesPoint represents a single data point in a time series.
|
||||
type TimeSeriesPoint struct {
|
||||
Timestamp time.Time
|
||||
Count int64
|
||||
}
|
||||
|
||||
// HourlyCount represents the total attempts for a given hour of day.
|
||||
type HourlyCount struct {
|
||||
Hour int // 0-23
|
||||
Count int64
|
||||
}
|
||||
|
||||
// CountryCount represents the total attempts from a given country.
|
||||
type CountryCount struct {
|
||||
Country string
|
||||
Count int64
|
||||
}
|
||||
|
||||
// DashboardFilter contains optional filters for dashboard queries.
|
||||
type DashboardFilter struct {
|
||||
Since *time.Time
|
||||
Until *time.Time
|
||||
IP string
|
||||
Country string
|
||||
Username string
|
||||
}
|
||||
|
||||
// TopEntry represents a value and its count for top-N queries.
|
||||
type TopEntry struct {
|
||||
Value string
|
||||
@@ -127,6 +154,30 @@ type Store interface {
|
||||
// sessions left over from a previous unclean shutdown.
|
||||
CloseActiveSessions(ctx context.Context, disconnectedAt time.Time) (int64, error)
|
||||
|
||||
// GetAttemptsOverTime returns daily attempt counts for the last N days.
|
||||
GetAttemptsOverTime(ctx context.Context, days int, since, until *time.Time) ([]TimeSeriesPoint, error)
|
||||
|
||||
// GetHourlyPattern returns total attempts grouped by hour of day (0-23).
|
||||
GetHourlyPattern(ctx context.Context, since, until *time.Time) ([]HourlyCount, error)
|
||||
|
||||
// GetCountryStats returns total attempts per country, ordered by count DESC.
|
||||
GetCountryStats(ctx context.Context) ([]CountryCount, error)
|
||||
|
||||
// GetFilteredDashboardStats returns aggregate counts with optional filters applied.
|
||||
GetFilteredDashboardStats(ctx context.Context, f DashboardFilter) (*DashboardStats, error)
|
||||
|
||||
// GetFilteredTopUsernames returns top usernames with optional filters applied.
|
||||
GetFilteredTopUsernames(ctx context.Context, limit int, f DashboardFilter) ([]TopEntry, error)
|
||||
|
||||
// GetFilteredTopPasswords returns top passwords with optional filters applied.
|
||||
GetFilteredTopPasswords(ctx context.Context, limit int, f DashboardFilter) ([]TopEntry, error)
|
||||
|
||||
// GetFilteredTopIPs returns top IPs with optional filters applied.
|
||||
GetFilteredTopIPs(ctx context.Context, limit int, f DashboardFilter) ([]TopEntry, error)
|
||||
|
||||
// GetFilteredTopCountries returns top countries with optional filters applied.
|
||||
GetFilteredTopCountries(ctx context.Context, limit int, f DashboardFilter) ([]TopEntry, error)
|
||||
|
||||
// Close releases any resources held by the store.
|
||||
Close() error
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user