Transparenz schafft Vertrauen – doch ein schlecht isoliertes Dashboard wird zum LGPD-Vorfall. Servicekennzahlen mit dem Kunden zu teilen reduziert Nachfragen per E-Mail und zeigt Professionalität. Die technische Herausforderung ist nicht, das Diagramm zu zeichnen: Es geht darum sicherzustellen, dass jeder Kunde nur seine eigenen Tickets sieht. So setzen Sie das mit GLPI + Metabase oder Grafana um, mit dem Filter nach Einheit an der richtigen Stelle fixiert.
Vor der Freigabe: drei Entscheidungen, die alles bestimmen
Beim Betrieb von GLPI-Umgebungen mit mehreren Kunden entscheiden drei Weichenstellungen, ob das Dashboard ein Alleinstellungsmerkmal oder ein Sicherheitsproblem wird:
- Wo der Filter nach Einheit fixiert wird: im Link, in der Abfrage oder im signierten Embed. Nur Letzteres widersteht einer Manipulation der URL.
- Welches Datum für den Zeitraum gilt: Erstellung (
date), Lösung (solvedate) oder Abschluss (closedate). Wer die drei vermischt, verzerrt alle Kennzahlen. - Woher die Daten gelesen werden: Primärdatenbank oder schreibgeschützte Replik. Metabase und Grafana feuern schwere Abfragen ab und konkurrieren mit GLPI in der Produktion.
Schritt 1 – schreibgeschützter Datenbankbenutzer
Richten Sie das BI-Werkzeug nie auf den GLPI-Benutzer aus. Legen Sie einen eigenen Benutzer mit SELECT und nichts darüber hinaus an. In MariaDB:
-- Read-only user for BI, restricted to the internal network
CREATE USER 'bi_ro'@'10.20.%' IDENTIFIED BY '...strong_password...';
GRANT SELECT ON glpi.* TO 'bi_ro'@'10.20.%';
-- Per-query time limit keeps a dashboard from stalling the database (MariaDB)
SET GLOBAL max_statement_time = 15; -- seconds
FLUSH PRIVILEGES;
Wenn möglich, richten Sie das BI auf eine Lese-Replik statt auf die Primärdatenbank aus. So blockiert ein vergessener Filter in einem Diagramm keine GLPI-Transaktionen in der Produktion – wir haben erlebt, wie ein einziges Panel mit schlecht geschriebenem JOIN die Antwortzeit des gesamten Helpdesks verschlechtert hat.
Schritt 2 – nach Einheit isolieren, ohne Untereinheiten zu verlieren
Jeder Kunde ist in GLPI eine Einheit, und der erste Impuls ist, nach entities_id = X zu filtern. Hier liegt die häufigste Falle: Hat der Kunde Filialen oder Abteilungen als Untereinheiten, erfasst dieser Filter nur die Stammeinheit, und die Zahlen fallen kleiner aus als in der Realität. Der gesamte Teilbaum muss einbezogen werden. Ab MariaDB 10.2.2 gelingt das mit einer rekursiven CTE:
-- All of the client's entities (root + descendants)
WITH RECURSIVE client_tree AS (
SELECT id FROM glpi_entities WHERE id = 4 -- client's root entity
UNION ALL
SELECT e.id
FROM glpi_entities e
JOIN client_tree c ON e.entities_id = c.id
)
SELECT
COUNT(*) AS total,
SUM(t.status IN (1,2,3,4)) AS open_tickets,
SUM(t.status IN (5,6)) AS closed_tickets
FROM glpi_tickets t
WHERE t.entities_id IN (SELECT id FROM client_tree)
AND t.is_deleted = 0;
Beachten Sie das is_deleted = 0: GLPI verwendet logisches Löschen, und ohne diesen Filter fließen Tickets im Papierkorb in die Zählung ein. Das ist der zweithäufigste Fehler, den wir in Dashboards korrigieren, die wir von einem anderen Team übernehmen.
Schritt 3 – SLA, ohne den Prozentsatz aufzublähen
Die SLA-Erfüllungsquote wirkt trivial: vor der Frist gelöst, gezählt. Das täuschende Detail steckt im Feld time_to_resolve (der im Ticket gespeicherten SLA-Frist): Es ist NULL, wenn dem Ticket kein SLA zugeordnet ist. Vergleichen Sie solvedate <= time_to_resolve, ohne NULL zu behandeln, verschwinden diese Tickets aus dem Nenner, und der Prozentsatz steigt künstlich. Machen Sie die Grundgesamtheit explizit:
WITH RECURSIVE client_tree AS (
SELECT id FROM glpi_entities WHERE id = 4
UNION ALL
SELECT e.id FROM glpi_entities e
JOIN client_tree c ON e.entities_id = c.id
)
SELECT
COUNT(*) AS with_sla,
SUM(t.solvedate <= t.time_to_resolve) AS on_time,
ROUND(100 * SUM(t.solvedate <= t.time_to_resolve) / COUNT(*), 1) AS sla_pct
FROM glpi_tickets t
WHERE t.entities_id IN (SELECT id FROM client_tree)
AND t.is_deleted = 0
AND t.time_to_resolve IS NOT NULL -- only tickets with an SLA
AND t.solvedate IS NOT NULL -- already solved
AND t.date >= '2026-06-01'
AND t.date < '2026-07-01';
Welche Kennzahlen für den Kunden sinnvoll sind
Nicht alles, was das interne Team verfolgt, ist für den Kunden interessant – oder sollte ihm gezeigt werden. Ein schlankes Set funktioniert besser:
- Operativ: offene Tickets nach Status und Priorität, eröffnete vs. abgeschlossene im Zeitraum, durchschnittliche Reaktions- und Lösungszeit.
- SLA: Anteil innerhalb der Frist und gefährdete Tickets (kurz vor Ablauf von
time_to_resolve). - Zufriedenheit: Durchschnittsnote der Umfrage (
glpi_ticketsatisfactions) und monatlicher Trend. - Vertrag: verbrauchte vs. vertraglich vereinbarte Stunden und Restguthaben, wenn es ein Stundenkontingent gibt.
Wo der Filter fixiert wird: Entscheidungsmatrix
Der heikelste Punkt ist zu verhindern, dass der Kunde den Parameter in der URL ändert und Daten eines anderen sieht. Jede Methode löst den Filter an einer anderen Stelle auf:
| Methode | Wo der Filter angewendet wird | Risiko eines Datenlecks | Aufwand | Wann einsetzen |
|---|---|---|---|---|
| Metabase – öffentlicher Link | Editierbarer Parameter in der URL | Hoch | Niedrig | Nur für interne Demos, nie mit Kundendaten |
| Metabase – signierter Embed (JWT) | Auf dem Server fixierter Parameter (Token) | Niedrig | Mittel | Empfohlener Standard für Kunden |
| Grafana – anonymer Zugriff | Legt die gesamte Organisation offen | Hoch | Niedrig | Vermeiden |
| Grafana – Public Dashboards (9.1+) | Ein Dashboard pro Link, ohne editierbare Variable | Mittel | Niedrig | Einzelner Kunde, ohne sensible Untereinheiten |
| Grafana – Organisation pro Kunde | Isoliert per Org + Proxy | Niedrig | Hoch | Viele Kunden, starke Isolation |
Die Falle, die am teuersten war (im Betrieb)
In einer Umgebung mit Dutzenden Einheiten zeigte das Dashboard eines Kunden etwa die Hälfte der Tickets, die der manuelle Bericht auswies. Die Ursache war nicht die Zählabfrage – es war der öffentliche Link von Metabase. Der Filter nach Einheit war als Dashboard-Parameter angelegt, und jeder mit dem Link konnte den Wert in der URL ändern und durch andere Einheiten navigieren. Wir haben auf einen signierten Embed (JWT) umgestellt, mit der in das Token injizierten entities_id und dem als locked markierten Parameter. Der Kunde verlor die Möglichkeit, am Filter zu drehen, und erhielt eine Zahl, die endlich mit dem Vertrag übereinstimmte. Die Lehre, die wir in jedes Projekt mitnehmen: Die Sicherheit des Dashboards liegt nicht in der Abfrage, sondern darin, wo der Filter aufgelöst wird.
Checkliste für die Veröffentlichung
- Schreibgeschützter Datenbankbenutzer, vorzugsweise auf eine Replik ausgerichtet.
- Filter nach Einheit einschließlich des Teilbaums (rekursive CTE oder Liste von IDs).
is_deleted = 0in jeder Abfrage aufglpi_tickets.- Konsistenter Zeitraum: Wählen Sie ein Datum (Erstellung, Lösung oder Abschluss) und verwenden Sie es in allen Kacheln.
- Auf dem Server fixierter Filter (signierter Embed), nie nur in der URL.
- Test des Links mit einem externen Benutzer, bevor er an den Kunden geht.
Sie brauchen Kunden-Dashboards mit auslaufsicherer Isolation nach Einheit? NexTool implementiert und betreibt GLPI-Umgebungen mit integriertem BI (Metabase und Grafana) und LGPD-konformer Data Governance. Lernen Sie den Support- und Betriebsservice kennen oder lesen Sie den Vergleich Metabase vs. Grafana und die wesentlichen KPIs für den Service Desk.
Geprüft vom Team von NexTool Solutions.