Technischer Engineering-Report: gghstats-Ökosystem v1.5.1

1. Kontext und Designphilosophie
GitHub-Traffic-Daten (Views und Clones) bleiben nur in einem rollierenden 14-Tage-Fenster. Ohne eigene Erfassung ist diese Telemetrie weg. gghstats speichert Traffic-Historie in SQLite, mit Dashboard, API, CLI und Prometheus-Metriken — Serien über das API-Limit hinaus.

Das Design priorisiert Datensouveränität und operativen Minimalismus: ein Go-Binary + SQLite, keine Pflicht-Fremddatenbank, Self-Hosting statt SaaS mit PAT bei Dritten.
Trennung der Verantwortlichkeiten
| Repository | Rolle |
|---|---|
| gghstats (Core) | Anwendung: GitHub-Sync → SQLite, serve, API/UI, CLI, Prometheus, opt-in Alerts, GHCR-Image / Binaries. App-Env wie GGHSTATS_DB, GGHSTATS_TRUSTED_PROXIES, GGHSTATS_GITHUB_TOKEN usw. |
| gghstats-selfhosted (Deploy) | Operator-IaC: Compose (minimal / Traefik TLS / Observability), Helm, GGHSTATS_HOST_DATA-Layout, Image-Pin, VPS-Docs. Nicht der Engine-Quellcode. |

Traefik, Helm, Grafana/Prometheus/Loki-Stacks und die Konvention GGHSTATS_HOST_DATA gehören zu selfhosted. Der Core liefert nur Binary/Image und die Semantik der Anwendungsvariablen (z. B. Vertrauen in X-Forwarded-* via GGHSTATS_TRUSTED_PROXIES).
2. Installation und Deploy
Schnelle Evaluation (Core)
| Methode | Befehl / Tool | Nutzung |
|---|---|---|
| Script | curl -fsSL https://get.gghstats.com/install.sh | sh |
Schnellinstall Linux/macOS (Pin: VERSION=v1.5.1 …) |
| Homebrew | brew install hrodrig/gghstats/gghstats |
Workstations |
| Go | go install github.com/hrodrig/gghstats/cmd/gghstats@latest |
Quelle / bleeding-edge |
Demo-Modus: gghstats serve --demo (oder GGHSTATS_DEMO=true) — UI mit synthetischen Daten, ohne PAT und ohne echten Sync.
Produktion: was wo lebt
Core (Anwendung):
- SQLite-Persistenz:
GGHSTATS_DB/--db(im Container oft/data/gghstats.dbmit Volume auf/data). - Hinter Reverse Proxy:
GGHSTATS_TRUSTED_PROXIES(CIDR/IP des Peers zu gghstats), damit Rate-Limit / Whitelist / Access-Log den echten Client viaX-Forwarded-For/X-Real-IPnutzen. Leere Liste = Header ignorieren (sicheres Default). - Image:
ghcr.io/hrodrig/gghstatsaufgcr.io/distroless/static-debian13:nonroot.
Selfhosted (Manifeste): Repo-Version ~0.1.58, App-Pin GGHSTATS_VERSION=v1.5.1.
GGHSTATS_HOST_DATA: Host-Verzeichnis (z. B./home/gghstats/gghstats-data) mit.env, SQLite unter/data, optional.env.observability/ Theme-CSS. Compose mit--env-file "${GGHSTATS_HOST_DATA}/.env".- Compose minimal: ein Service, Host-Port (z. B. 8080).
- Compose Traefik: HTTPS (80/443), Let’s Encrypt (
GGHSTATS_HOSTNAME,ACME_EMAIL). Edge- + App-Rate-Limit;/metricsnicht im öffentlichen Router (interner Scrape). Optional Authelia-SSO aufgghstats_edge. - Observability (optional, braucht Traefik /
gghstats_edge): Prometheus, Grafana, Loki; Compose-Projekt-p gghstats-obs; Traefik-Overlay für Grafana auf eigener FQDN. - Helm: Chart
gghstatsvonhttps://hrodrig.github.io/gghstats-selfhosted(oder Clone./run/kubernetes/helm/gghstats); Token im Secret; PVC auf/data. - Image-Upgrade:
GGHSTATS_VERSIONändern →pull+up -d(restartreicht nicht). Helper:./run/scripts/compose-stack.sh.
Alerts (Slack / Webhook / Loki / SMTP) gehören zum Core (GGHSTATS_ALERTS_*); selfhosted verdrahtet nur die Vars in Compose/Helm und dokumentiert gghstats alert test.
3. Verlauf: v1.1.0 → v1.5.1
v1.1.0 — Pins + Featured (Migration v6)
- CLI
gghstats repo/gghstats featured: Pins unionieren in die Traffic-Menge (FILTER ∪ pins); Featured ist redaktionelle Vitrine ohne Traffic auf/. - Tabellen
pinsundfeatured(Migration v6). - Seite
/featured(neo-brutalistisches Grid); Nav-Link nur bei nicht-leerem Katalog.
v1.2.0 — Featured-UX + Zahlen
- Zahlenformatierung (Trennzeichen /
GGHSTATS_COMPACT_NUMBERS). /featured: Pagination, Suche und Sortierung (page,per_page,q,sort,dir) viaFilterFeatured.
v1.3.0 — Index-Statistik + JSONL
- Tägliches Clone-Statistik-Panel, Rank/
# - %, Unique-Linie im Index-Chart. - JSONL-Export vom Index (Summary + Historie + Referrers/Paths/Stars pro gefiltertem Repo). Entsteht hier; Traffic-API/SQLite-Schema unverändert.
v1.4.0 — Uniques-UX + Featured-JSON + UTC-Stempel
- U1: Uniques als Primärzahl; Clone/View-Events sekundär.
GET /api/v1/featured+/featuredin der Sitemap (bei Einträgen).- JSONL:
Content-Dispositionmit UTC-Stempelgghstats-export-YYYYMMDD-HHMM.jsonl(#23). Carlok-Fixes #22–#25 (Locale-Charts, Tooltips, Rank).
v1.5.0 — Fünf Reporting-Slices
| Slice | Inhalt |
|---|---|
| F-fresh | Frische/Coverage pro Metrik (views / clones). Statuses: fresh | delayed | missing | failed | never. Charts mit null-Lücken (explizite Null ≠ weggelassener Tag). Unabhängiger Views/Clones-Fetch. Migration v7 (traffic_metric_state, traffic_metric_coverage). |
| V-vis | github_visibility + report_policy (exclude > include > inherit); GGHSTATS_REPORT_PRIVATE; CLI repo report ls/set. Report-Oberflächen fail-closed (ununterscheidbarer 404). Collection (Filter/Pins/INCLUDE_PRIVATE) getrennt vom Reporting. Migration v8. |
| V-json | gghstats repo report ls --json (+ Filter --visibility / --policy) für Post-Upgrade-Skripte. |
| U-legend | i18n-Legende in Detail-Charts: Lücke/null = von GitHub nicht gemeldet; 0 = bestätigte Null. |
| X-chart | Chart-alignierter JSON-Download (/{owner}/{repo}/traffic.json); Dogfood …/traffic?dense=1 (Sparse-Default unverändert). |
Operatoren: nach 1.5.0 bestehende Zeilen → unknown + inherit bis zum nächsten Sync (oder repo report set … include). SQLite-Historie wird nicht gelöscht; Dashboard/APIs/Exports/Badges können bis dahin leer wirken.
v1.5.1 — Featured-Fix (#47)
In 1.5.0 wurde Featured fälschlich als Report-Oberfläche behandelt: /featured, API, Nav und Sitemap verlangten eine gesammelte repos-Zeile und reportVisible. Das zerbricht die redaktionelle Vitrine (Featured-Eintrag ≠ Traffic-Repo).
1.5.1 stellt den Katalog wieder her: erneut FilterFeatured / FeaturedCount. Report-Sichtbarkeit gilt weiter nur für Traffic/Dashboard-Routen. Kein Sync nötig für die Vitrine. Kein Aufweichen des Dashboard-Fail-Closed; der Bug war der falsche Scope von Featured.
4. Daten, Sicherheit und Supply Chain
Relevante SQLite-Migrationen
| Version | Inhalt |
|---|---|
| v6 | pins, featured |
| v7 | Traffic-Frische / Coverage |
| v8 | repos.github_visibility, repos.report_policy |
Öffnung mit WAL für parallele Reads (UI/API) während Sync schreibt.
Defense in depth (Core)
- Token-Bucket-Rate-Limiting pro IP; optionale IP-Whitelist;
GGHSTATS_API_ONLY. GGHSTATS_TRUSTED_PROXIES(siehe §2).- Cosign + SBOM in Releases; Testabdeckung ≥ 80 % im Release-Check.
- Distroless-Nonroot-Image.
Alerts
Opt-in (GGHSTATS_ALERTS_ENABLED): Sinks Slack / Webhook / Loki / SMTP; Regeln nach Sync; Prüfung mit gghstats alert test. Grafana/Loki-Stacks in Observability Compose sind selfhosted-Deploy, getrennt vom Loki-Sink der App.
5. Abschluss
v1.5.1 festigt die 1.5-Linie: ehrliche Frische (fünf Status + null-Lücken), fail-closed Report-Sichtbarkeit mit Migrationen v7/v8 und den Fix, dass Featured ein redaktioneller Katalog ist, kein Report-Scope. Die Engine bleibt in gghstats; Traefik, Helm, GGHSTATS_HOST_DATA und Observability leben in gghstats-selfhosted, mit Image-Pin v1.5.1.
Referenzen: CHANGELOG · SPEC · Core-README · gghstats-selfhosted · Install https://get.gghstats.com/install.sh