Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/server/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ func routeDescriptions() map[string]routeMeta {
{Name: "from", Description: "RFC3339 start; if from or to is given, window is ignored (an unparseable value leaves that bound open)", Type: "string"},
{Name: "to", Description: "RFC3339 end; if from or to is given, window is ignored (an unparseable value leaves that bound open)", Type: "string"},
}},
"GET /api/scope-audit": {Summary: "Declared versus observed forwarding scopes", Description: "Observer-confirmed scope declarations compared with collision-safe flood path evidence. Missing observations are not proof of a configuration error. Unknown scopes, ambiguous hops, absent observations, and declarations older than seven days make evidence incomplete. Observer scope lists may be truncated without a completeness flag. Cached 30 seconds for each of three supported windows; identity visibility is applied live.", Tag: "analytics", QueryParams: []paramMeta{{Name: "window", Description: "Observation window: 1h, 24h (default), or 7d", Type: "string"}}},
"GET /api/analytics/wardriving": {Summary: "Wardriving channel analytics", Description: "Activity/entry-point/coverage/signal/session analytics for the #wardriving channel (or another channel via ?channel=): message volume over time, top senders, path[0] entry-point hash-prefix tallies (resolve names via /api/resolve-hops), per-observer coverage (observer's known IATA-derived coordinates, not the sender's — MeshMapper's wardriving messages normally carry an anonymous session token, not live GPS), average SNR/RSSI over the same time buckets as the activity series, each sender's messages grouped into distinct sessions/runs (split on a 15-minute gap, each with an AirtimeMs field — LoRa Time-on-Air × distinct relaying repeaters, same formula as the Overview tab's Relay Airtime Share, omitted in DB-only mode), and any senders who explicitly shared their own position (some clients append plaintext \"<lat>,<lon>\" after the token — a deliberate choice by that sender, confirmed empirically, not something CoreScope infers). Cached 30s per window+channel.", Tag: "analytics",
QueryParams: []paramMeta{
{Name: "window", Description: "Time window: 1h, 24h (default), or 7d", Type: "string"},
Expand Down
4 changes: 4 additions & 0 deletions cmd/server/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ type Server struct {
scopeStatsCache map[string]*ScopeStatsResponse
scopeStatsCachedAt map[string]time.Time

// Cached /api/scope-audit response — per-window, recomputed at most once every 30s
scopeAudit scopeAuditCache

// Cached /api/analytics/wardriving response — per-window, recomputed at most once every 30s
wardrivingStatsMu sync.Mutex
wardrivingStatsCache map[string]*WardrivingStatsResponse
Expand Down Expand Up @@ -323,6 +326,7 @@ func (s *Server) RegisterRoutes(r *mux.Router) {
r.HandleFunc("/api/health", s.handleHealth).Methods("GET")
r.HandleFunc("/api/stats", s.handleStats).Methods("GET")
r.HandleFunc("/api/scope-stats", s.handleScopeStats).Methods("GET")
r.HandleFunc("/api/scope-audit", s.handleScopeAudit).Methods("GET")
r.HandleFunc("/api/analytics/hop-depth", s.handleHopDepthAnalytics).Methods("GET")
r.HandleFunc("/api/analytics/wardriving", s.handleWardrivingStats).Methods("GET")
r.HandleFunc("/api/analytics/wardriving/sender-messages", s.handleWardrivingSenderMessages).Methods("GET")
Expand Down
Loading
Loading