WAU Compliance: agent collector, backend endpoints, frontend badge + panel

- Agent: WAU registry config check (include/exclude URLs), pending updates count
- Backend: /wau/compliance per customer, /wau/compliance/summary all customers
- Frontend: compliance badge in customer list, compliance panel in WAU tab
- config.js: no longer gitignored (secrets-free, reads from env/window.__RMM_CONFIG__)
- vite.config.js: reads backend URL from .env instead of hardcoded value
- .env.example added for clean setup
This commit is contained in:
cynfo3000
2026-03-10 17:38:58 +01:00
parent bf51ed8569
commit 54ddc0b902
12 changed files with 677 additions and 19 deletions
+55 -3
View File
@@ -10,10 +10,14 @@ import (
// setupWAURoutes registriert alle WAU-Endpunkte
func (h *Handler) setupWAURoutes(mux *http.ServeMux) {
// Authentifizierte Endpunkte (API-Key oder JWT)
mux.HandleFunc("GET /api/v1/customers/{id}/wau/rules", h.listWAURules)
mux.HandleFunc("POST /api/v1/customers/{id}/wau/rules", h.addWAURule)
mux.HandleFunc("GET /api/v1/customers/{id}/wau/rules", h.listWAURules)
mux.HandleFunc("POST /api/v1/customers/{id}/wau/rules", h.addWAURule)
mux.HandleFunc("DELETE /api/v1/customers/{id}/wau/rules/{rid}", h.deleteWAURule)
mux.HandleFunc("GET /api/v1/customers/{id}/wau/inventory", h.getWAUInventory)
mux.HandleFunc("GET /api/v1/customers/{id}/wau/inventory", h.getWAUInventory)
mux.HandleFunc("GET /api/v1/customers/{id}/wau/compliance", h.getWAUCompliance)
// Compliance-Summary für alle Kunden
mux.HandleFunc("GET /api/v1/wau/compliance/summary", h.getWAUComplianceSummary)
// Plaintext-Endpunkte für WAU (kein Auth nötig — enthält nur App-IDs)
mux.HandleFunc("GET /api/v1/customers/{id}/wau/included", h.wauIncludedList)
@@ -149,3 +153,51 @@ func (h *Handler) serveWAUList(w http.ResponseWriter, r *http.Request, ruleType
w.Write([]byte("\r\n"))
}
}
// wauExpectedURLs leitet die erwarteten WAU-URLs aus dem Request-Host ab
func wauExpectedURLs(r *http.Request, customerID int) (includeURL, excludeURL string) {
scheme := "https"
if r.TLS == nil && (r.Header.Get("X-Forwarded-Proto") == "" || r.Header.Get("X-Forwarded-Proto") == "http") {
scheme = "http"
}
if fwd := r.Header.Get("X-Forwarded-Proto"); fwd != "" {
scheme = fwd
}
host := r.Host
base := scheme + "://" + host
includeURL = base + "/api/v1/customers/" + strconv.Itoa(customerID) + "/wau/included"
excludeURL = base + "/api/v1/customers/" + strconv.Itoa(customerID) + "/wau/excluded"
return
}
// GET /api/v1/customers/{id}/wau/compliance
func (h *Handler) getWAUCompliance(w http.ResponseWriter, r *http.Request) {
customerID, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
writeError(w, http.StatusBadRequest, "Ungültige Kunden-ID")
return
}
includeURL, excludeURL := wauExpectedURLs(r, customerID)
agents, err := h.db.GetWAUCompliance(customerID, includeURL, excludeURL)
if err != nil {
writeError(w, http.StatusInternalServerError, "Fehler beim Laden der Compliance-Daten")
return
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"agents": agents,
"include_url": includeURL,
"exclude_url": excludeURL,
})
}
// GET /api/v1/wau/compliance/summary — Zusammenfassung für alle Kunden
func (h *Handler) getWAUComplianceSummary(w http.ResponseWriter, r *http.Request) {
// Ohne customer_id können wir keine URLs ableiten — wir geben Summary ohne URL-Check zurück
// oder nutzen customer_id=0 als Wildcard (kein URL-Check)
summaries, err := h.db.GetAllCustomersWAUSummary("", "")
if err != nil {
writeError(w, http.StatusInternalServerError, "Fehler beim Laden der Compliance-Daten")
return
}
writeJSON(w, http.StatusOK, summaries)
}