diff --git a/src/components/Footer.astro b/src/components/Footer.astro index 7b016f5..ff9175c 100644 --- a/src/components/Footer.astro +++ b/src/components/Footer.astro @@ -19,6 +19,7 @@ const groups = [ links: [ { label: "Documentation", href: withBase("/docs/") }, { label: "Changelog", href: withBase("/docs/changelog/") }, + { label: "Telemetry", href: withBase("/telemetry/") }, { label: "GitHub", href: GITHUB_URL }, ], }, diff --git a/src/content/docs/air-gapped-installation.mdx b/src/content/docs/air-gapped-installation.mdx index 94c31bd..2a5e96f 100644 --- a/src/content/docs/air-gapped-installation.mdx +++ b/src/content/docs/air-gapped-installation.mdx @@ -329,6 +329,19 @@ helm upgrade gameplane oci://registry.internal.corp/gameplane/charts-gameplane \ Confirm the operator and API pods roll with the new image digest, and re-run GameServer tests above. +### Disable usage telemetry + +New installs send anonymous usage reports to the project's provider at `telemetry.gameplane.net` unless told otherwise. An air-gapped cluster cannot reach it, and the reporter would retry for nothing. Turn telemetry off at install time so the API never attempts the connection, whatever an admin later toggles: + +```yaml +# values-offline.yaml +api: + telemetry: + enabled: false +``` + +With `api.telemetry.enabled=false` no first-login notice is shown and Admin Settings > Telemetry shows both switches as unavailable. To keep usage figures inside the cluster instead, leave telemetry enabled and set `api.telemetry.receiver.enabled=true` (the bundled receiver, mirrored as `telemetry-receiver` in the image list above), or point `api.telemetry.endpoint` at an internal receiver. See [Platform settings, telemetry, and build info](../platform-settings-telemetry/) and the [data-handling statement](https://gameplane.net/telemetry/). + ### Test with egress fully blocked If possible, disconnect the cluster from the public internet (or block all egress via NetworkPolicy) and repeat the above tests to confirm every artifact is truly local. A 404 or timeout on any pull request confirms you missed an image. @@ -339,5 +352,6 @@ If possible, disconnect the cluster from the public internet (or block all egres "01 Mirror chart + images + modules + signatures + SBOMs by digest", "02 Render offline; reject public hosts and mutable tags", "03 Test install, server, backup, upgrade, rollback with egress blocked", + "04 Set api.telemetry.enabled=false (or an internal endpoint) so no report leaves the cluster", ]} /> diff --git a/src/content/docs/helm-values-reference.mdx b/src/content/docs/helm-values-reference.mdx index 9021b79..c06b640 100644 --- a/src/content/docs/helm-values-reference.mdx +++ b/src/content/docs/helm-values-reference.mdx @@ -128,7 +128,8 @@ Configure logging, metrics, and alerting sinks. | `api.audit.syslogBridge.enabled` | boolean | `false` | Deploy the bundled RFC 5424 syslog bridge (audit-syslog-bridge image). When enabled and `webhook.url` is unset, the API auto-wires to it. | | `api.audit.syslogBridge.syslog.addr` | string | *(empty — required if enabled)* | Syslog collector address in `host:port` format, e.g., `syslog.example:514`. | | `api.audit.syslogBridge.syslog.network` | enum | `tcp` | Syslog transport: `tcp` (recommended for reliability) or `udp` (no delivery confirmation). | -| `api.telemetry.endpoint` | string | *(empty)* | External telemetry receiver URL, e.g., `https://telemetry.example.com/ingest`. Disables the bundled receiver auto-wiring. | +| `api.telemetry.enabled` | boolean | `true` | Hard on/off for usage telemetry. `false` means the API never sends telemetry, whatever the admin switches say, and no first-login notice is shown. Use it for air-gapped and privacy-sensitive clusters. | +| `api.telemetry.endpoint` | string | *(empty)* | Where reports go. Empty means the project's default provider, `https://telemetry.gameplane.net/ingest`. Set a URL such as `https://telemetry.example.com/ingest` to send reports to your own receiver instead; it replaces the default and disables the bundled receiver auto-wiring. | | `serviceMonitors.enabled` | boolean | `false` | Create Prometheus Operator ServiceMonitor resources for scraping Gameplane metrics. Requires Prometheus Operator to be installed in your cluster. | ## Storage and modules @@ -179,7 +180,16 @@ Configure optional integrations. | Key | Type | Default | Description | |---|---|---|---| | `mcpServer.enabled` | boolean | `false` | Deploy a read-only Model Context Protocol (MCP) server for AI assistant integrations. It reads 7 Gameplane CRDs (not `Cluster`, nor `NetworkCapture`, the ninth CRD added in v0.3.0), plus Pods, Events and pod logs. Read-only, stdio JSON-RPC only (no network port). See `mcp-server/README.md`. | -| `api.telemetry.receiver.enabled` | boolean | `false` | Deploy the bundled telemetry receiver (telemetry-receiver image) for opt-in anonymous usage stats. When enabled and `endpoint` is unset, the API auto-wires to it. Admin toggle in dashboard controls whether anything is sent. | +| `api.telemetry.receiver.enabled` | boolean | `false` | Deploy the bundled telemetry receiver (telemetry-receiver image). When enabled and `endpoint` is unset, the API auto-wires to it, so reports stay in your cluster. Admin switches in the dashboard control whether anything is sent. | +| `api.telemetry.receiver.persistence.enabled` | boolean | `true` | Keep the receiver's aggregates in a PVC at `/data` (`persistence.size`, default `1Gi`). With `false` an emptyDir is used and everything is lost on restart. While on, `receiver.replicas` must stay `1`. | +| `api.telemetry.receiver.dashboard.tokenSecretRef.name` | string | *(empty)* | Secret holding the receiver's dashboard token (key `token`, at least 32 characters). Setting it starts the private dashboard listener on port 8081; reach it with `kubectl port-forward`. | +| `api.telemetry.receiver.pepperSecretRef.name` | string | *(empty)* | Optional Secret (key `pepper`) with the HMAC pepper for install IDs. Empty means the receiver generates and stores one. | +| `api.telemetry.receiver.publicSummary.enabled` | boolean | `false` | Serve five public aggregate counters on `GET /v1/summary`. | +| `api.telemetry.receiver.retentionDays` | integer | `730` | Daily aggregate retention (minimum `365`). | +| `api.telemetry.receiver.activityExpiryDays` | integer | `90` | Per-install activity record expiry (minimum `31`). | +| `api.telemetry.receiver.ingestPow.enabled` | boolean | `false` | Require proof-of-work on report ingestion (tuned by `targetPerMinute` `60`, `minBits` `0`, `maxBits` `22`; `maxBits` at most `26`). Meant for a public provider. | + +To run a receiver for other installs, see [Run a telemetry provider on Kubernetes](../telemetry-provider-kubernetes/). ## Example: minimal production install diff --git a/src/content/docs/platform-settings-telemetry.mdx b/src/content/docs/platform-settings-telemetry.mdx index 41e3212..592ae1e 100644 --- a/src/content/docs/platform-settings-telemetry.mdx +++ b/src/content/docs/platform-settings-telemetry.mdx @@ -1,6 +1,6 @@ --- title: "Platform settings, telemetry, and build info" -description: "Maintain instance identity and defaults, make an explicit telemetry choice, and capture exact build data for support." +description: "Maintain instance identity and defaults, review the telemetry tiers and opt-out, and capture exact build data for support." section: "platform" group: "audit-observability" order: 7 @@ -44,26 +44,33 @@ Keep instance name, canonical external URL, and default namespace stable and env ## Telemetry and privacy -Usage telemetry is an explicit choice and is not a substitute for operational metrics and logs. +Usage telemetry is on by default for new installs and is not a substitute for operational metrics and logs. Reports go to the project's provider at `telemetry.gameplane.net` unless the operator chose another destination or disabled telemetry. The project's [data-handling statement](../../telemetry/) lists exactly what is collected and how long it is kept. -When enabled, the API sends a daily anonymous report containing only the cluster version, count of active GameServers, and count of GameTemplates. The current implementation excludes server names, player counts, and identifying data. +On a new install the first admin to sign in sees a notice naming the destination and both tiers; nothing is sent until an admin has seen it. Admin Settings > Telemetry then shows the destination, a preview of the next report, the last attempt, separate switches for the basic and extended tiers, and an install-ID reset. Turning basic off turns extended off with it. + +**Basic** sends only the Gameplane version, the GameServer count and the GameTemplate count. **Extended** adds a random install ID, the Kubernetes minor version, a distribution category, CPU architectures and a node-count band, server counts per official module (custom modules are one combined count), feature adoption flags and bands, the database kind, the UI language, a public signing key and the send time. Every value comes from a fixed set or is a number; names, namespaces, hostnames, addresses and player data are never sent. @@ -88,7 +95,7 @@ Before opening a support ticket or upgrading: label="PLATFORM RECORD" items={[ "Stable instance name + canonical URL + intentional namespace", - "Explicit telemetry choice; operational monitoring remains separate", + "Telemetry tiers chosen on purpose (or disabled at install); operational monitoring remains separate", "Record chart/image-tag/Kubernetes/values before support or upgrade", ]} /> diff --git a/src/content/docs/telemetry-provider-kubernetes.mdx b/src/content/docs/telemetry-provider-kubernetes.mdx new file mode 100644 index 0000000..31dd976 --- /dev/null +++ b/src/content/docs/telemetry-provider-kubernetes.mdx @@ -0,0 +1,362 @@ +--- +title: "Run a telemetry provider on Kubernetes" +description: "Deploy a standalone Gameplane telemetry receiver with TLS, a private dashboard and proof-of-work, using plain manifests." +section: "platform" +group: "audit-observability" +order: 8 +icon: "server" +sidebarLabel: "Telemetry provider on Kubernetes" +eyebrow: "OPERATIONS" +readTime: "10 MIN" +covers: ["Receiver", "Ingress", "NetworkPolicy"] +--- + +import DocsCallout from "../../components/docs/DocsCallout.astro"; +import DocsQuickReference from "../../components/docs/DocsQuickReference.astro"; + + +Installs send telemetry to the project's provider by default; you only need your own provider to collect reports from several installs or to keep data in-house. For one install, use the bundled receiver (`api.telemetry.receiver.enabled`) instead. + + +This page sets up a standalone provider in its own namespace, `gameplane-telemetry`. It follows the shape of the project's provider at `telemetry.gameplane.net`: Cloudflare's proxy in front, Traefik on k3s as the ingress, a certificate from cert-manager through a Cloudflare DNS-01 challenge, a private dashboard and proof-of-work. + +Other ingress controllers and CDNs work the same way. The parts to adapt are the Ingress annotations, the NetworkPolicy peer and `TRUSTED_PROXY_CIDRS`. The repository ships no manifests for this, so copy the ones below. + +## Prerequisites + +- k3s (or any cluster) with Traefik as the ingress controller in `kube-system`, configured to trust Cloudflare's forwarded headers. `forwardedHeaders.trustedIPs` on the `web` and `websecure` entry points must list Cloudflare's ranges, and Traefik must see Cloudflare's address as the peer (for example `service.spec.externalTrafficPolicy: Local` with ServiceLB). The [client address check](#check-the-client-address) below confirms both. +- cert-manager. +- The zone (`gameplane.net` here) on Cloudflare, and a Cloudflare API token with Zone:DNS:Edit and Zone:Zone:Read on it. +- A CNI that enforces NetworkPolicies (the kube-router that ships with k3s does). + +## 1. Namespace, secrets and trusted proxies + +```sh +kubectl create namespace gameplane-telemetry + +# Dashboard token: 32 random bytes = 44 base64 characters (the receiver refuses fewer than 32). +kubectl -n gameplane-telemetry create secret generic telemetry-dashboard \ + --from-literal=token="$(openssl rand -base64 32)" + +# ID pepper: set it before the first report and never lose it (see Rotating secrets). +kubectl -n gameplane-telemetry create secret generic telemetry-pepper \ + --from-literal=pepper="$(openssl rand -base64 32)" + +# Trusted proxies: the cluster's pod CIDR (where Traefik runs) plus Cloudflare's published ranges. +# CHANGE ME if your cluster is not on the k3s default. +# Check with: kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}' +POD_CIDR=10.42.0.0/16 +CF_RANGES=$( { curl -fsS https://www.cloudflare.com/ips-v4; echo; curl -fsS https://www.cloudflare.com/ips-v6; } | grep . | paste -sd, - ) +kubectl -n gameplane-telemetry create configmap telemetry-trusted-proxies \ + --from-literal=cidrs="${POD_CIDR},${CF_RANGES}" \ + --dry-run=client -o yaml | kubectl apply -f - + +# Check the result: the pod CIDR first, then Cloudflare's IPv4 and IPv6 ranges +# (for example 10.42.0.0/16,173.245.48.0/20,...,2400:cb00::/32,...). +kubectl -n gameplane-telemetry get configmap telemetry-trusted-proxies -o jsonpath='{.data.cidrs}'; echo +``` + +The list is a static copy. Cloudflare changes its ranges rarely; when it does, rerun the last two commands and restart the receiver with `kubectl -n gameplane-telemetry rollout restart deploy/telemetry-receiver`, because the variable is read at start. Update Traefik's `forwardedHeaders.trustedIPs` the same way. If you prefer, set `TRUSTED_PROXY_CIDRS` as a literal `value:` in the Deployment instead of the ConfigMap reference; the receiver reads only the environment variable. [How the client address is resolved](#5-how-the-client-address-is-resolved) explains why the list matters. For the token and pepper, see [Secrets](https://github.com/ValgulNecron/Gameplane/blob/master/docs/telemetry-provider.md#secrets) and [Rotating secrets](https://github.com/ValgulNecron/Gameplane/blob/master/docs/telemetry-provider.md#rotating-secrets). + +## 2. Certificate issuer (cert-manager DNS-01 through Cloudflare) + +Skip this step if you already have a ClusterIssuer for the zone. Otherwise store the Cloudflare API token and create the issuer: + +```sh +# CHANGE ME: your Cloudflare API token. +kubectl -n cert-manager create secret generic cloudflare-api-token \ + --from-literal=api-token='' +``` + +```yaml +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-cloudflare +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: you@example.com # CHANGE ME + privateKeySecretRef: + name: letsencrypt-cloudflare-account + solvers: + - dns01: + cloudflare: + apiTokenSecretRef: + name: cloudflare-api-token + key: api-token + selector: + dnsZones: [gameplane.net] # CHANGE ME: your zone +``` + +DNS-01 works with the Cloudflare proxy on, because validation never goes through the proxied hostname. + +## 3. Receiver, Service, Ingress and NetworkPolicy + +Save the following as `telemetry-provider.yaml` and apply it with `kubectl apply -f telemetry-provider.yaml`. It holds five documents: the volume, the receiver, its Service, the Ingress and the NetworkPolicy. + +```yaml +# 1. Storage: the SQLite database lives here (/data/telemetry.db). +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: telemetry-receiver-data + namespace: gameplane-telemetry +spec: + accessModes: [ReadWriteOnce] + # storageClassName: fast-ssd # CHANGE ME, or omit to use the cluster default + resources: + requests: + storage: 1Gi +--- +# 2. The receiver. One replica and Recreate: one process owns the SQLite file. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: telemetry-receiver + namespace: gameplane-telemetry + labels: + app.kubernetes.io/name: telemetry-receiver +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: telemetry-receiver + template: + metadata: + labels: + app.kubernetes.io/name: telemetry-receiver + spec: + securityContext: + runAsNonRoot: true + runAsUser: 65532 + fsGroup: 65532 + seccompProfile: + type: RuntimeDefault + containers: + - name: receiver + image: ghcr.io/valgulnecron/gameplane/telemetry-receiver:edge # CHANGE ME: pin a release tag + imagePullPolicy: Always # edge moves; use IfNotPresent once you pin a release tag + env: + - { name: LISTEN_ADDR, value: ":8080" } + - { name: DATA_DIR, value: "/data" } + - name: DASHBOARD_TOKEN + valueFrom: + secretKeyRef: { name: telemetry-dashboard, key: token } + - name: ID_PEPPER + valueFrom: + secretKeyRef: { name: telemetry-pepper, key: pepper } + - name: TRUSTED_PROXY_CIDRS + valueFrom: + configMapKeyRef: { name: telemetry-trusted-proxies, key: cidrs } + - { name: PUBLIC_SUMMARY, value: "true" } + - { name: RETENTION_DAYS, value: "730" } + - { name: ACTIVITY_EXPIRY_DAYS, value: "90" } + - { name: INGEST_SOURCE_DAILY_LIMIT, value: "20" } + - { name: INGEST_POW, value: "true" } + - { name: INGEST_POW_TARGET_PER_MIN, value: "60" } + - { name: INGEST_POW_MIN_BITS, value: "0" } + - { name: INGEST_POW_MAX_BITS, value: "22" } + ports: + - { name: http, containerPort: 8080 } + - { name: dashboard, containerPort: 8081 } + livenessProbe: + httpGet: { path: /healthz, port: http } + initialDelaySeconds: 5 + readinessProbe: + httpGet: { path: /healthz, port: http } + initialDelaySeconds: 2 + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: [ALL] + volumeMounts: + - { name: data, mountPath: /data } + volumes: + - name: data + persistentVolumeClaim: + claimName: telemetry-receiver-data +--- +# 3. Service: ingest is public (through the Ingress), the dashboard stays cluster-internal. +apiVersion: v1 +kind: Service +metadata: + name: telemetry-receiver + namespace: gameplane-telemetry + labels: + app.kubernetes.io/name: telemetry-receiver +spec: + selector: + app.kubernetes.io/name: telemetry-receiver + ports: + - { name: ingest, port: 8080, targetPort: http } + - { name: dashboard, port: 8081, targetPort: dashboard } +--- +# 4. Ingress for Traefik: publishes only the public listener's routes, never :8081. +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: telemetry-receiver + namespace: gameplane-telemetry + annotations: + cert-manager.io/cluster-issuer: letsencrypt-cloudflare + traefik.ingress.kubernetes.io/router.entrypoints: websecure +spec: + ingressClassName: traefik + tls: + - hosts: [telemetry.gameplane.net] # CHANGE ME + secretName: telemetry-gameplane-net-tls + rules: + - host: telemetry.gameplane.net # CHANGE ME + http: + paths: + - { path: /ingest, pathType: Exact, backend: { service: { name: telemetry-receiver, port: { name: ingest } } } } + - { path: /v1/challenge, pathType: Exact, backend: { service: { name: telemetry-receiver, port: { name: ingest } } } } + - { path: /v1/summary, pathType: Exact, backend: { service: { name: telemetry-receiver, port: { name: ingest } } } } + - { path: /healthz, pathType: Exact, backend: { service: { name: telemetry-receiver, port: { name: ingest } } } } +--- +# 5. NetworkPolicy: 8080 only from the Traefik pods, 8081 only from the +# monitoring namespace (kubectl port-forward is not affected), no egress. +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: telemetry-receiver + namespace: gameplane-telemetry +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: telemetry-receiver + policyTypes: [Ingress, Egress] + ingress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + podSelector: + matchLabels: + app.kubernetes.io/name: traefik + ports: + - { protocol: TCP, port: 8080 } + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: monitoring # CHANGE ME, or remove this rule + ports: + - { protocol: TCP, port: 8081 } + # The receiver makes no outbound connections: no DNS, no Kubernetes API, no other service. + egress: [] +``` + +Key points: + +- Values to change are marked `# CHANGE ME`: the image tag, the storage class, the hostname (in the Ingress `tls` and `rules`), the ClusterIssuer email and zone, the Cloudflare API token, the monitoring namespace, and `POD_CIDR` if your cluster is not on the k3s default. Also replace `telemetry.gameplane.net` in the Cloudflare rule and in the Verify commands. +- The provider features (dashboard, signed extended reports, proof-of-work) ship in the first release after v0.3.0. Pin that release or a later one. A v0.3.0 or older receiver has no dashboard and no `/v1/challenge`, and answers 400 to extended reports, so installs fall back to basic-only reports for 7 days. +- `edge` follows master. If you run it, keep `imagePullPolicy: Always` so that a restart pulls the latest build; with `IfNotPresent` a node keeps the image it already has. +- One replica with `Recreate`, because SQLite has a single writer. `fsGroup: 65532` makes `/data` writable for the distroless nonroot user. +- `AUTH_TOKEN` is deliberately unset: a public provider accepts reports from any install. +- `ID_PEPPER` is recommended. Without it the receiver generates a pepper and stores it in the database, so it is lost with the volume. +- Proof-of-work is on with the defaults (target 60 challenges per minute, 0 to 22 bits). See [Proof-of-work on ingest](https://github.com/ValgulNecron/Gameplane/blob/master/docs/telemetry-provider.md#proof-of-work-on-ingest) to tune it. +- `PUBLIC_SUMMARY` is on, so `/v1/summary` is routed. If you turn it off, remove that path from the Ingress. +- If the probes fail after the NetworkPolicy is applied (some CNIs block the node's own probe traffic), add an `ipBlock` for your node addresses to the 8080 rule. + +## 4. Cloudflare settings + +1. DNS: add an `A` record (and an `AAAA` record if you have IPv6) named `telemetry` that points at the cluster's public address, set to **Proxied** (orange cloud). +2. SSL/TLS encryption mode: **Full (strict)**. The origin presents the cert-manager certificate. +3. Bot protection: installs send plain HTTP POSTs with no browser, so a challenge page breaks them (they record `failed` and retry). Keep **Bot Fight Mode** off for the zone, because on the Free plan it cannot be skipped per hostname. Add a WAF custom rule `(http.host eq "telemetry.gameplane.net")` with the action **Skip** for Super Bot Fight Mode, Browser Integrity Check and Security Level (and managed rules, if they challenge it). +4. Caching: add no "Cache Everything" rule for this hostname. `/v1/challenge` sends `Cache-Control: no-store`, and `/ingest` is a POST. +5. Managed Transforms: keep **Remove visitor IP headers** off. It strips `X-Forwarded-For`, and every install would then share one source address. +6. Optional: add a Cloudflare rate-limiting rule on `/ingest` as a first line of defense in front of proof-of-work. +7. Optional: allow only Cloudflare's ranges to reach port 443 on the origin (host firewall, or Authenticated Origin Pulls), so that nobody can bypass the rules above. + +## 5. How the client address is resolved + +The receiver rate-limits per source address, so it needs the install's address, not the proxy's. An install connects to Cloudflare, which adds `X-Forwarded-For: `. Traefik trusts Cloudflare's ranges, keeps that header and appends the Cloudflare edge address, so the receiver sees `X-Forwarded-For: , `. The TCP peer of the receiver is the Traefik pod, inside the pod CIDR. + +When the peer is inside `TRUSTED_PROXY_CIDRS`, the receiver takes the right-most `X-Forwarded-For` entry that is not itself trusted. That is why the list needs both the pod CIDR (for Traefik) and Cloudflare's ranges (to skip the edge address). Without Cloudflare's ranges, every install is attributed to one of a handful of edge addresses, and the per-source limits (20 reports a day, and the `/v1/challenge` burst) throttle all installs together. + +A client outside Cloudflare's ranges cannot choose its source address. Anything it puts in `X-Forwarded-For` stays to the left of the real entry and is ignored, and proof-of-work still applies to every request. A request that bypasses Cloudflare reaches Traefik from an untrusted address, so Traefik drops its `X-Forwarded-For`. An unparsable header falls back to the peer address. The address is used only in memory for rate limiting and is never stored; see [Source addresses and `TRUSTED_PROXY_CIDRS`](https://github.com/ValgulNecron/Gameplane/blob/master/docs/telemetry-provider.md#source-addresses-and-trusted_proxy_cidrs). + +For a provider without a CDN, trust only the ingress controller's pod CIDR. + +## 6. Verify + +```sh +kubectl -n gameplane-telemetry rollout status deploy/telemetry-receiver +# Expect READY True. +kubectl -n gameplane-telemetry get certificate telemetry-gameplane-net-tls +# Expect: ok +curl -fsS https://telemetry.gameplane.net/healthz +# The public counters. +curl -fsS https://telemetry.gameplane.net/v1/summary +# A challenge (proof-of-work is on). +curl -fsS https://telemetry.gameplane.net/v1/challenge +# Expect 404: the metrics port 8081 is not routed. +curl -sS -o /dev/null -w '%{http_code}\n' https://telemetry.gameplane.net/metrics +``` + +### Check the client address + +The receiver never logs addresses, so check what Traefik forwards with a throwaway echo service on the same host, then delete it: + +```sh +kubectl -n gameplane-telemetry create deployment whoami --image=traefik/whoami +kubectl -n gameplane-telemetry expose deployment whoami --port 80 +kubectl -n gameplane-telemetry create ingress whoami --class=traefik \ + --rule="telemetry.gameplane.net/whoami-check=whoami:80,tls=telemetry-gameplane-net-tls" \ + --annotation traefik.ingress.kubernetes.io/router.entrypoints=websecure +kubectl -n gameplane-telemetry rollout status deploy/whoami +# If Traefik answers 404, it has not picked up the route yet: retry after a few seconds. +curl -fsS https://telemetry.gameplane.net/whoami-check | grep -i x-forwarded-for +# expect: X-Forwarded-For: , +kubectl -n gameplane-telemetry delete ingress,service,deployment whoami +``` + +The NetworkPolicy selects only the receiver pods, so the whoami pod is reachable. If the first entry is not your public address, or only one address appears, Traefik is not trusting Cloudflare or does not see Cloudflare's address as the peer. Fix that before going live. + +### Open the dashboard + +The dashboard on `:8081` is never routed. Reach it with a port-forward and sign in with the dashboard token: + +```sh +kubectl -n gameplane-telemetry port-forward svc/telemetry-receiver 8081:8081 +# in another terminal, print the token: +kubectl -n gameplane-telemetry get secret telemetry-dashboard -o jsonpath='{.data.token}' | base64 -d +``` + +Open `http://localhost:8081`. The session cookie is `Secure`, and browsers treat `localhost` as a secure origin, so sign-in works over plain HTTP there. + +## 7. Scrape metrics (optional) + +This needs the Prometheus Operator. The ServiceMonitor reads the same token Secret, and the NetworkPolicy above admits the `monitoring` namespace on 8081 only. + +```yaml +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: telemetry-receiver + namespace: gameplane-telemetry + # labels: { release: my-prometheus } # CHANGE ME, if your Prometheus selects ServiceMonitors by label +spec: + selector: + matchLabels: + app.kubernetes.io/name: telemetry-receiver + endpoints: + - port: dashboard + interval: 30s + path: /metrics + bearerTokenSecret: + name: telemetry-dashboard + key: token +``` + +## Upgrade and back up + +**Upgrade:** change the image tag in the manifest and run `kubectl apply -f telemetry-provider.yaml`. On `edge` with `imagePullPolicy: Always`, run `kubectl -n gameplane-telemetry rollout restart deploy/telemetry-receiver` instead. The Recreate strategy stops the old pod before the new one starts, so ingest returns 503 for a few seconds. Installs retry the next day or on their own backoff. + +**Back up first:** take a snapshot of the PVC, or stop the receiver (`kubectl -n gameplane-telemetry scale deploy/telemetry-receiver --replicas=0`) and copy the `/data` folder. See [Back up and restore `telemetry.db`](https://github.com/ValgulNecron/Gameplane/blob/master/docs/telemetry-provider.md#back-up-and-restore-telemetrydb) for details. + +**Secret rotation:** update the Secret, then restart with `kubectl -n gameplane-telemetry rollout restart deploy/telemetry-receiver`. See [Rotating secrets](https://github.com/ValgulNecron/Gameplane/blob/master/docs/telemetry-provider.md#rotating-secrets) for the effects. diff --git a/src/pages/telemetry.astro b/src/pages/telemetry.astro new file mode 100644 index 0000000..18b135d --- /dev/null +++ b/src/pages/telemetry.astro @@ -0,0 +1,104 @@ +--- +import MarketingLayout from "../layouts/MarketingLayout.astro"; +import SectionHeader from "../components/SectionHeader.astro"; +import { GITHUB_URL } from "../config"; +import { withBase } from "../lib/url"; +--- + + +
+ +
+

Who operates it

+

The Gameplane project maintainers run the default provider at telemetry.gameplane.net. Reports go to https://telemetry.gameplane.net/ingest. Anyone can run their own provider; this statement covers only the project's.

+ +

What is sent

+

Two tiers, about once a day, only while an admin has left them on.

+
    +
  • Basic: exactly version (Gameplane version), servers (number of GameServers), templates (number of GameTemplates).
  • +
  • Extended (adds only the following): a random install ID (a UUID generated on the install, not derived from the cluster, host, network or users); environment: Kubernetes minor version, a distribution category (k3s, rke2, k0s, eks, gke, aks, openshift, microk8s, minikube, kind, doks, talos or other), CPU architectures, and a node-count band (1, 2-3, 4-10, 11-50, 51+); game usage: a server count for each official catalog module plus one combined custom count; feature adoption: wake-on-connect, relay tunnel types (frp, tailscale, playit), packet capture, backups, single sign-on, audit forwarding (each yes/no), a registered-cluster band (1, 2-3, 4-10, 11+), database kind (sqlite or postgres) and UI language; the install's public signing key and the time the report was sent.
  • +
  • Every extended value comes from a fixed set of categories or bands, or is a number, the install ID, the public key or the send time; anything else is sent as other.
  • +
+ +

Signing and the install ID

+

Extended reports are signed (Ed25519) with a key derived from a random secret that never leaves the install combined with the install ID; the provider binds an ID to the first key that uses it, so nobody can report under another install's ID. Signing proves which key sent a report, not that the install is real; figures are approximate and self-reported. The ID is pseudonymous: it lets the provider tell that two reports came from the same install. An admin can reset it in Admin Settings, and it is deleted from the install when extended telemetry is turned off.

+ +

What is never collected

+

Server names, namespaces, hostnames, player counts or names, custom module names, free text, or any address or identifier of your cluster, network or users. The provider does not store raw reports and does not store source network addresses. The report format cannot hold any of these.

+

Requests to telemetry.gameplane.net pass through Cloudflare's proxy, which sees the connecting address to deliver the request and handles it under Cloudflare's own privacy policy. The receiver uses the address only in memory to rate-limit and never stores it.

+ +

What the provider stores

+ + + + + + + + + + + + + + + + + + + + + +
CategoryContents
Daily aggregatesCounts per day by version, fleet-size band, and for extended reports counts by environment, game and feature category; never linked to an install ID
Activity recordsA one-way keyed hash of the install ID, a fingerprint of the public key, first-seen and last-seen dates, last send time and last version; used for unique-install and new/lapsed counts
Total-reports counterA single number only
+ +

How long

+ + + + + + + + + + + + + + + + + + + + + + + + + +
DataRetention
Daily aggregates24 months (730 days), deleted by an hourly sweep
Activity records90 days after the install's last report
Total-reports counterKept indefinitely
Source addressesMemory only, never written to disk
+ +

Abuse protection

+

Reports are strictly validated (one JSON object, size cap 16 KiB, fixed-set values); per-source daily limit; proof-of-work on submission whose cost is zero under normal traffic and grows only with the request rate (installs refuse challenges above 26 bits); the dashboard is private (token of at least 32 characters, never public). Someone can still send fabricated reports, so figures are approximate.

+ +

Public summary

+

https://telemetry.gameplane.net/v1/summary returns exactly five numbers: asOf date, reports on the latest day, reports in 30 days, total reports, and active installs in 30 days. Nothing else is public; the detailed dashboard is private to the maintainers.

+ +

How to opt out

+
    +
  • At first login: A notice appears before any report is sent, showing both tiers and the destination. Admin Settings > Telemetry then shows separate basic and extended switches (turning basic off turns extended off).
  • +
  • At install time: Set --set api.telemetry.enabled=false to hard-disable telemetry whatever the switches say, with no notice shown.
  • +
  • Custom provider: Set api.telemetry.endpoint=https://your-host/ingest to send to your own provider instead and never also to the project's.
  • +
  • Existing installs that never saved a choice stay off after upgrading.
  • +
+

See the docs on platform settings, telemetry, and build info, the Helm values reference, and air-gapped installation.

+ +

Questions and requests

+

Open an issue on GitHub; the maintainers operate the provider.

+
+
+ diff --git a/website-export/MANIFEST.md b/website-export/MANIFEST.md index 5ff4efd..d2aa0e4 100644 --- a/website-export/MANIFEST.md +++ b/website-export/MANIFEST.md @@ -6,9 +6,9 @@ Snapshot of `website.pen` (Pencil, MCP-only) for review in git. Full re-export 2 | Set | Count | Notes | |---|---|---| -| Screens + local website components (Nav `Qczsa`, Footer `gnZrl`, Docs Top Bar `SOdlr`, Reference Top Bar `egO9x`, Badge/Outline `X4Xyl`, Docs/Expanded Sidebar `K2Rt4H`) | 102 | 96 `Screen/…` frames + 6 components | +| Screens + local website components (Nav `Qczsa`, Footer `gnZrl`, Docs Top Bar `SOdlr`, Reference Top Bar `egO9x`, Badge/Outline `X4Xyl`, Docs/Expanded Sidebar `K2Rt4H`) | 104 | 98 `Screen/…` frames + 6 components | | HeroUI components (children of container `hYJwr`, "HeroUI: Design System Components") | 177 | copied from the dashboard's `design.pen` | -| **Total** | **279** | `json/.json` + `screenshots/.png` each | +| **Total** | **281** | `json/.json` + `screenshots/.png` each | The lunaris library (`H:`-prefixed ids and variables) was removed from the design; its 100 exports were deleted. @@ -59,3 +59,22 @@ Docs screens updated to mirror the `docs: sync the docs with the main repo's Oct not re-exported). - JSON: `Print(JSON.stringify(Get(id, {depth: 30, includePathGeometry: true})))`, re-serialized with `jq .`; `jq empty` passes, zero `"..."` elisions, node counts match the live file. Screenshots: `Export([id], "png", …, {scale: 2})`. + +## 2026-10-07 incremental: telemetry + +Spec 022 (default telemetry) in the main repo: footer link, docs updates and two new pages +(`src/pages/telemetry.astro`, `src/content/docs/telemetry-provider-kubernetes.mdx`). + +- New screens: `s0Q7Lf` (Docs — Telemetry Provider on Kubernetes, copied from `cpCjN`; next link → Modules & Sources) + and `K6tq5Z` (Telemetry Statement, copied from `ei1qC`). +- Footer `gnZrl`: "Telemetry" link before GitHub in the Resources column; the inline mobile footer on `JjbY2` gets the + same link. +- Text updates: `cpCjN` (Platform Settings: telemetry text, quick reference, next link → Telemetry Provider on + Kubernetes), `kTRsn` (Helm Values Reference: new Telemetry block for `api.telemetry.enabled`, `api.telemetry.endpoint`, + `api.telemetry.receiver.enabled`), `zeM79` (Air-gapped Installation: new section "Disable usage telemetry"). +- Heights changed: `kTRsn` 1100, `zeM79` 1060. +- Re-exported: JSON + screenshots for `gnZrl` `JjbY2` `cpCjN` `kTRsn` `zeM79` `s0Q7Lf` `K6tq5Z`; screenshots only for + the screens whose footer instance changed but whose JSON did not: `B39hL` `hnTHJ` `ei1qC` `vh8hz` `tfxmL` `IGuE6`. +- JSON: `JSON.stringify(Get(id, {depth: 30, includePathGeometry: true}))`, checked against the length and FNV-1a hash + Pencil printed, then pretty-printed (2-space indent, UTF-8, trailing newline); zero `"..."` elisions. Screenshots: + `export_nodes` at 2×. diff --git a/website-export/json/JjbY2.json b/website-export/json/JjbY2.json index f10dcb4..7ed0a35 100644 --- a/website-export/json/JjbY2.json +++ b/website-export/json/JjbY2.json @@ -47,7 +47,7 @@ "type": "image", "enabled": true, "url": "design-assets/gameplane-icon.png", - "mode": "fill" + "mode": "cover" }, "cornerRadius": "$radius/md", "justifyContent": "center", @@ -914,7 +914,7 @@ "type": "image", "enabled": true, "url": "design-assets/gameplane-icon.png", - "mode": "fill" + "mode": "cover" }, "cornerRadius": "$radius/md", "justifyContent": "center", @@ -1040,6 +1040,15 @@ "fontSize": 13, "fontWeight": "normal" }, + { + "type": "text", + "id": "i8tUo", + "fill": "$muted", + "content": "Telemetry", + "fontFamily": "$typography/font-sans", + "fontSize": 13, + "fontWeight": "normal" + }, { "type": "text", "id": "yNiWc", diff --git a/website-export/json/K6tq5Z.json b/website-export/json/K6tq5Z.json new file mode 100644 index 0000000..b1cc966 --- /dev/null +++ b/website-export/json/K6tq5Z.json @@ -0,0 +1,778 @@ +{ + "type": "frame", + "id": "K6tq5Z", + "x": 0, + "y": 120468, + "name": "Screen/Telemetry Statement", + "theme": { + "semantic": "dark" + }, + "width": 1440, + "fill": "$background/background", + "layout": "vertical", + "children": [ + { + "id": "PdJ8e", + "type": "ref", + "ref": "Qczsa", + "name": "Nav", + "width": "fill_container" + }, + { + "type": "frame", + "id": "OUmXG", + "name": "CompareBody", + "width": "fill_container", + "fill": "$background/background", + "layout": "vertical", + "gap": 48, + "padding": [ + 80, + 80, + 96, + 80 + ], + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "qo6MM", + "name": "header", + "width": "fill_container", + "layout": "vertical", + "gap": 12, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "a8t4F", + "fill": "$accent/accent", + "content": "TELEMETRY", + "textAlign": "center", + "fontFamily": "$typography/font-mono", + "fontSize": 12, + "fontWeight": "600", + "letterSpacing": 1 + }, + { + "type": "text", + "id": "slZsE", + "fill": "$foreground/foreground", + "textGrowth": "fixed-width", + "width": 760, + "content": "Telemetry data-handling statement", + "textAlign": "center", + "fontFamily": "$typography/font-mono", + "fontSize": 34, + "fontWeight": "700" + }, + { + "type": "text", + "id": "Yh3u2", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": 760, + "content": "Last updated 2026-10-07.", + "textAlign": "center", + "fontFamily": "$typography/font-sans", + "fontSize": 16, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "GTNTv", + "name": "Statement Article", + "width": 780, + "layout": "vertical", + "gap": 14, + "children": [ + { + "type": "frame", + "id": "cIqhi", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "vDbJD", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Who operates it", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "L7CpT", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The project maintainers run the default provider at telemetry.gameplane.net; anyone can run their own. This statement covers only the project's.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "FVk7Z", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "b8KAG1", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "What is sent", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "SU5Ke", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Two tiers, about once a day, only while an admin leaves them on.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "Q183g", + "name": "Section List 1", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "dpiXu", + "name": "Section 1 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "PqLHX", + "name": "Section 1 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "IhwQy", + "name": "Section 1 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Basic: version, servers (GameServer count) and templates (GameTemplate count).", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "x9o0L", + "name": "Section 1 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "OH7vg", + "name": "Section 1 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "ep1Ap", + "name": "Section 1 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Extended adds: random install ID, Kubernetes minor, distribution, architectures, node-count band.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "S4RzSN", + "name": "Section 1 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "L79w87", + "name": "Section 1 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "NC4AK", + "name": "Section 1 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Also per-module server counts, feature flags and bands, database kind, UI language, public key, send time.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "U5KLl", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "s9Soql", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Signing and the install ID", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "Qb50x", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Extended reports are signed (Ed25519) so nobody can report under another install's ID. The ID is pseudonymous; an admin can reset it, and it is deleted when extended is turned off.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "y2Woc", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "m5x3Q", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "What is never collected", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "A4Dzf", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Server names, namespaces, hostnames, player data, custom module names, free text, or any cluster, network or user address. Raw reports and source addresses are not stored.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "nFcmz", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "mlrJf", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "What the provider stores", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "d1jyC", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Daily aggregates, activity records and a total-reports counter.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "uiOWJ", + "name": "Section List 1", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "s2dHPF", + "name": "Section 1 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "S4xx2", + "name": "Section 1 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "YLcxz", + "name": "Section 1 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Daily aggregates: counts by version, fleet-size band and category, never linked to an install ID.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "P1eejb", + "name": "Section 1 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "S7sTv6", + "name": "Section 1 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "lnrR1", + "name": "Section 1 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Activity records: keyed hash of the install ID, key fingerprint, first/last seen, last version.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "cB3db", + "name": "Section 1 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "TSFRP", + "name": "Section 1 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "rvvnu", + "name": "Section 1 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Total-reports counter: a single number.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "t0qQ5B", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "NWxP8", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "How long", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "G5KyWM", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Aggregates 24 months; activity records 90 days after the last report; source addresses never written to disk.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "pYTx1", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "k3JsKp", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Abuse protection", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "O81l3", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Strict validation (16 KiB cap), per-source daily limit, proof-of-work that costs nothing in normal traffic, and a private token-protected dashboard.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "UoRma", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "a6pUwo", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Public summary", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "sKDfN", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "GET /v1/summary returns exactly five numbers; the detailed dashboard is private to the maintainers.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "GVGJA", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "vbCKO", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "How to opt out", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "DTDuT", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Notice before the first report, then separate switches in Admin Settings > Telemetry.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "epdW6", + "name": "Section List 1", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "x80Spm", + "name": "Section 1 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "OYJHO", + "name": "Section 1 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "f4kxVu", + "name": "Section 1 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "At first login: separate basic and extended switches; basic off turns extended off.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "p9saIX", + "name": "Section 1 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "tz1ws", + "name": "Section 1 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "XulJR", + "name": "Section 1 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "At install time: --set api.telemetry.enabled=false is a hard off with no notice.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "u1pPo", + "name": "Section 1 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "hipxx", + "name": "Section 1 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "KSniZ", + "name": "Section 1 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Custom provider: api.telemetry.endpoint=https://your-host/ingest replaces the project's.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "r5thm", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "hHeyP", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Questions and requests", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "u4JLM1", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Open an issue on GitHub; the maintainers operate the provider.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "id": "CZkko", + "type": "ref", + "ref": "gnZrl", + "name": "Footer", + "width": "fill_container" + } + ] +} diff --git a/website-export/json/cpCjN.json b/website-export/json/cpCjN.json index 61e5e66..ee0c6d7 100644 --- a/website-export/json/cpCjN.json +++ b/website-export/json/cpCjN.json @@ -93,7 +93,7 @@ "fill": "$muted", "textGrowth": "fixed-width", "width": "fill_container", - "content": "Maintain instance identity and defaults, make an explicit telemetry choice, and capture exact build data for support.", + "content": "Maintain instance identity and defaults, review the telemetry tiers and opt-out, and capture exact build data for support.", "lineHeight": 1.45, "fontFamily": "Geist", "fontSize": 15, @@ -355,7 +355,7 @@ "fill": "$muted", "textGrowth": "fixed-width", "width": "fill_container", - "content": "Usage telemetry is an explicit choice and is not a substitute for operational metrics and logs.", + "content": "On by default for new installs; reports go to the project's provider unless an operator disables or redirects them.", "lineHeight": 1.45, "fontFamily": "Geist", "fontSize": 13, @@ -403,7 +403,7 @@ "fill": "$default/foreground", "textGrowth": "fixed-width", "width": "fill_container", - "content": "The current promise excludes server names, players, and identifying data.", + "content": "Basic sends version and two counts; extended adds coarse environment and usage bands.", "fontFamily": "Geist", "fontSize": 12.5, "fontWeight": "normal" @@ -435,7 +435,7 @@ "fill": "$default/foreground", "textGrowth": "fixed-width", "width": "fill_container", - "content": "Document any required organizational privacy review.", + "content": "Set api.telemetry.enabled=false for a hard off; api.telemetry.endpoint redirects reports.", "fontFamily": "Geist", "fontSize": 12.5, "fontWeight": "normal" @@ -467,7 +467,7 @@ "fill": "$default/foreground", "textGrowth": "fixed-width", "width": "fill_container", - "content": "Recheck the saved choice after upgrades.", + "content": "Installs that never saved a choice stay off after an upgrade; recheck the setting.", "fontFamily": "Geist", "fontSize": 12.5, "fontWeight": "normal" @@ -549,7 +549,7 @@ "id": "f3i2WR", "name": "Quick Reference Line 2", "fill": "$foreground/foreground", - "content": "02 Explicit telemetry choice; operational monitoring remains separate", + "content": "02 Telemetry tiers chosen on purpose (or disabled at install); monitoring stays separate", "fontFamily": "JetBrains Mono", "fontSize": 11.5, "fontWeight": "normal" @@ -610,7 +610,7 @@ "id": "biGQY", "name": "Next Link Title", "fill": "$foreground/foreground", - "content": "Modules & Sources", + "content": "Telemetry provider on Kubernetes", "fontFamily": "JetBrains Mono", "fontSize": 13, "fontWeight": "500" diff --git a/website-export/json/gnZrl.json b/website-export/json/gnZrl.json index e465ffc..8878971 100644 --- a/website-export/json/gnZrl.json +++ b/website-export/json/gnZrl.json @@ -54,7 +54,7 @@ "type": "image", "enabled": true, "url": "design-assets/gameplane-icon.png", - "mode": "fill" + "mode": "cover" }, "cornerRadius": "$radius/md", "justifyContent": "center", @@ -197,6 +197,16 @@ "fontSize": 13, "fontWeight": "normal" }, + { + "type": "text", + "id": "A07NYu", + "name": "Telemetry", + "fill": "$muted", + "content": "Telemetry", + "fontFamily": "$typography/font-sans", + "fontSize": 13, + "fontWeight": "normal" + }, { "type": "text", "id": "XUlGh", diff --git a/website-export/json/kTRsn.json b/website-export/json/kTRsn.json index 49d4a2f..5fdcef9 100644 --- a/website-export/json/kTRsn.json +++ b/website-export/json/kTRsn.json @@ -9,7 +9,7 @@ }, "clip": true, "width": 1440, - "height": 900, + "height": 1100, "fill": "$background/background", "children": [ { @@ -1475,6 +1475,514 @@ } ] }, + { + "type": "frame", + "id": "tRi5P", + "name": "Reference Block 2", + "width": "fill_container", + "layout": "vertical", + "gap": 7, + "children": [ + { + "type": "text", + "id": "ve1hm", + "name": "Reference Block Title 2", + "fill": "$foreground/foreground", + "content": "Telemetry", + "fontFamily": "JetBrains Mono", + "fontSize": 14, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "GJJ49", + "name": "Reference Table 2", + "clip": true, + "width": "fill_container", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "IXzky", + "name": "Reference Table Header 2", + "width": "fill_container", + "height": 32, + "fill": "$surface/surface", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "QrGUl", + "name": "Header 2 Cell 0", + "width": 270, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "FxMCK", + "name": "Header 2 Text 0", + "fill": "$field/placeholder", + "content": "KEY", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.5 + } + ] + }, + { + "type": "frame", + "id": "T3N3pu", + "name": "Header 2 Cell 1", + "width": 130, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "anzma", + "name": "Header 2 Text 1", + "fill": "$field/placeholder", + "content": "TYPE", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.5 + } + ] + }, + { + "type": "frame", + "id": "hbiyO", + "name": "Header 2 Cell 2", + "width": 150, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "o6NhB", + "name": "Header 2 Text 2", + "fill": "$field/placeholder", + "content": "DEFAULT", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.5 + } + ] + }, + { + "type": "frame", + "id": "bMBLB", + "name": "Header 2 Cell 3", + "width": "fill_container", + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "BlL2h", + "name": "Header 2 Text 3", + "fill": "$field/placeholder", + "content": "DESCRIPTION", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.5 + } + ] + } + ] + }, + { + "type": "frame", + "id": "uOCEr", + "name": "Reference 2 Row 0", + "width": "fill_container", + "height": 38, + "fill": "$background/background", + "stroke": "$separator/separator", + "strokeWidth": { + "top": 1 + }, + "strokeAlignment": "inner", + "strokeLinejoin": "round", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "CPSh7", + "name": "Reference 2 Row 0 Cell 0", + "width": 270, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "q6LPo", + "name": "Reference 2 Row 0 Text 0", + "fill": "$accent/soft-foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "api.telemetry.enabled", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "utLKh", + "name": "Reference 2 Row 0 Cell 1", + "width": 130, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "Jibby", + "name": "Reference 2 Row 0 Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "boolean", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "fa2Q9", + "name": "Reference 2 Row 0 Cell 2", + "width": 150, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "n2sEF0", + "name": "Reference 2 Row 0 Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "true", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "P1XviT", + "name": "Reference 2 Row 0 Cell 3", + "width": "fill_container", + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "KIoHQ", + "name": "Reference 2 Row 0 Text 3", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Hard on/off; false never sends and shows no first-login notice.", + "fontFamily": "Geist", + "fontSize": 11, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "Dh5IF", + "name": "Reference 2 Row 1", + "width": "fill_container", + "height": 38, + "fill": "$surface/secondary", + "stroke": "$separator/separator", + "strokeWidth": { + "top": 1 + }, + "strokeAlignment": "inner", + "strokeLinejoin": "round", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "iiEeS", + "name": "Reference 2 Row 1 Cell 0", + "width": 270, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "EfC1J", + "name": "Reference 2 Row 1 Text 0", + "fill": "$accent/soft-foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "api.telemetry.endpoint", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "IQOvT", + "name": "Reference 2 Row 1 Cell 1", + "width": 130, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "D1ap9", + "name": "Reference 2 Row 1 Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "url", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "ElCtX", + "name": "Reference 2 Row 1 Cell 2", + "width": 150, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "ar0Zh", + "name": "Reference 2 Row 1 Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "project provider", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "qV0zR", + "name": "Reference 2 Row 1 Cell 3", + "width": "fill_container", + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "MAoMo", + "name": "Reference 2 Row 1 Text 3", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Where reports go; set your own receiver URL to replace the default.", + "fontFamily": "Geist", + "fontSize": 11, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "RnTXg", + "name": "Reference 2 Row 2", + "width": "fill_container", + "height": 38, + "fill": "$background/background", + "stroke": "$separator/separator", + "strokeWidth": { + "top": 1 + }, + "strokeAlignment": "inner", + "strokeLinejoin": "round", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "h2N06B", + "name": "Reference 2 Row 2 Cell 0", + "width": 270, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "tVdo7", + "name": "Reference 2 Row 2 Text 0", + "fill": "$accent/soft-foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "api.telemetry.receiver.enabled", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "fOC6z", + "name": "Reference 2 Row 2 Cell 1", + "width": 130, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "EFsxL", + "name": "Reference 2 Row 2 Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "boolean", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "Cl31u", + "name": "Reference 2 Row 2 Cell 2", + "width": 150, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "wBDVq", + "name": "Reference 2 Row 2 Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "false", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "k6P2k", + "name": "Reference 2 Row 2 Cell 3", + "width": "fill_container", + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "tMUKA", + "name": "Reference 2 Row 2 Text 3", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Deploy the bundled receiver; reports stay inside the cluster.", + "fontFamily": "Geist", + "fontSize": 11, + "fontWeight": "normal" + } + ] + } + ] + } + ] + } + ] + }, { "type": "frame", "id": "uKwVB", diff --git a/website-export/json/s0Q7Lf.json b/website-export/json/s0Q7Lf.json new file mode 100644 index 0000000..7ddc39f --- /dev/null +++ b/website-export/json/s0Q7Lf.json @@ -0,0 +1,943 @@ +{ + "type": "frame", + "id": "s0Q7Lf", + "x": 0, + "y": 119308, + "name": "Screen/Docs — Telemetry Provider on Kubernetes", + "theme": { + "semantic": "dark" + }, + "clip": true, + "width": 1440, + "height": 900, + "fill": "$background/background", + "children": [ + { + "id": "QKRsx", + "type": "ref", + "ref": "K2Rt4H", + "height": "fill_container", + "name": "DocsSidebar/Expanded", + "width": 280 + }, + { + "type": "frame", + "id": "DROu9", + "name": "Docs Main", + "width": "fill_container", + "height": "fill_container", + "fill": "$background/background", + "layout": "vertical", + "children": [ + { + "id": "bO17d", + "type": "ref", + "ref": "SOdlr", + "name": "Docs Top Bar", + "width": "fill_container", + "descendants": { + "NImey": { + "content": "Platform" + }, + "ikbi6": { + "content": "Telemetry Provider" + } + } + }, + { + "type": "frame", + "id": "S5WmgI", + "name": "Docs Article Body", + "clip": true, + "width": "fill_container", + "height": "fill_container", + "gap": 32, + "padding": 32, + "children": [ + { + "type": "frame", + "id": "I8IIud", + "name": "Docs Article", + "width": 780, + "layout": "vertical", + "gap": 14, + "children": [ + { + "type": "text", + "id": "blRMz", + "name": "Article Eyebrow", + "fill": "$accent/accent", + "content": "OPERATIONS", + "fontFamily": "JetBrains Mono", + "fontSize": 11, + "fontWeight": "600", + "letterSpacing": 0.8 + }, + { + "type": "text", + "id": "kFlid", + "name": "Article Title", + "fill": "$foreground/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Run a telemetry provider on Kubernetes", + "lineHeight": 1.1, + "fontFamily": "JetBrains Mono", + "fontSize": 30, + "fontWeight": "700" + }, + { + "type": "text", + "id": "Dtwec", + "name": "Article Lead", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Deploy a standalone Gameplane telemetry receiver with TLS, a private dashboard and proof-of-work, using plain manifests.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 15, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "Lzi4R", + "name": "Article Metadata", + "gap": 8, + "alignItems": "center", + "children": [ + { + "id": "Bbhc7", + "type": "ref", + "ref": "NZPtq", + "name": "Meta Chip 0", + "descendants": { + "NLG8t": { + "content": "ADMIN GUIDE" + } + } + }, + { + "id": "I6iGr", + "type": "ref", + "ref": "EbSsA", + "name": "Meta Chip 1", + "descendants": { + "yb6zz": { + "content": "v0.3" + } + } + }, + { + "id": "uv7WH", + "type": "ref", + "ref": "EbSsA", + "name": "Meta Chip 2", + "descendants": { + "yb6zz": { + "content": "10 MIN" + } + } + } + ] + }, + { + "type": "frame", + "id": "c0ABw", + "name": "Article Callout", + "width": "fill_container", + "fill": "$accent/soft", + "cornerRadius": "$radius/xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "gap": 10, + "padding": [ + 10, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "ThyU7", + "name": "Article Callout Icon", + "width": 16, + "height": 16, + "icon": "shield-alert", + "library": "lucide", + "fill": "$accent/soft-foreground" + }, + { + "type": "text", + "id": "w0dKI", + "name": "Article Callout Text", + "fill": "$accent/soft-foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Most operators do not need this: installs report to the project's provider by default.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "s2Zsb4", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "VN4Wg", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Prerequisites", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "KCVXt", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Run it in its own namespace, gameplane-telemetry, on k3s or any cluster with Traefik, cert-manager and a Cloudflare zone.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "deZ4U", + "name": "Section List 1", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "sknwg", + "name": "Section 1 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "Pkqup", + "name": "Section 1 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "ebGaK", + "name": "Section 1 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Traefik trusts Cloudflare's forwarded headers (forwardedHeaders.trustedIPs).", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "dhggu", + "name": "Section 1 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "joqYN", + "name": "Section 1 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "I0dYh", + "name": "Section 1 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "cert-manager issues the certificate through a Cloudflare DNS-01 challenge.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "NNQms", + "name": "Section 1 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "danEX", + "name": "Section 1 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "T1x0C", + "name": "Section 1 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "A CNI that enforces NetworkPolicies (the kube-router that ships with k3s does).", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "VlhLM", + "name": "Guide Section 2", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "VJHMC", + "name": "Section Title 2", + "fill": "$foreground/foreground", + "content": "Deploy the receiver", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "F8yR0", + "name": "Section Body 2", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Secrets and trusted proxies, certificate issuer, then the receiver, Service, Ingress and NetworkPolicy.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "hbNTK", + "name": "Section List 2", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "f3nnPH", + "name": "Section 2 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "IOTII", + "name": "Section 2 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "j5ScU", + "name": "Section 2 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "One replica with Recreate; the SQLite database lives on a PVC at /data.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "htOVS", + "name": "Section 2 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "P717K2", + "name": "Section 2 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "Q20MTv", + "name": "Section 2 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The Ingress publishes only the public listener, never the dashboard on :8081.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "WVTQx", + "name": "Section 2 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "thS2Z", + "name": "Section 2 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "ulkKj", + "name": "Section 2 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "NetworkPolicy: 8080 from Traefik, 8081 from monitoring, no egress.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "FyxIG", + "name": "Guide Section 3", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "g6nDx9", + "name": "Section Title 3", + "fill": "$foreground/foreground", + "content": "Verify and operate", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "FlPrm", + "name": "Section Body 3", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Check readiness, the proof-of-work challenge and the client address; open the dashboard over port-forward.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "mOpLG", + "name": "Quick Reference", + "width": "fill_container", + "fill": "$surface/tertiary", + "cornerRadius": "$radius/xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 3, + "padding": 12, + "children": [ + { + "type": "text", + "id": "F52Z5", + "name": "Quick Reference Label", + "fill": "$accent/accent", + "content": "PROVIDER RUNBOOK", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.6 + }, + { + "type": "text", + "id": "MJqJo", + "name": "Quick Reference Line 1", + "fill": "$foreground/foreground", + "content": "01 kubectl apply -f telemetry-provider.yaml", + "fontFamily": "JetBrains Mono", + "fontSize": 11.5, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "tOURa", + "name": "Quick Reference Line 2", + "fill": "$foreground/foreground", + "content": "02 kubectl -n gameplane-telemetry port-forward svc/telemetry-receiver 8081:8081", + "fontFamily": "JetBrains Mono", + "fontSize": 11.5, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "wZhrZ", + "name": "Quick Reference Line 3", + "fill": "$foreground/foreground", + "content": "03 kubectl -n gameplane-telemetry rollout restart deploy/telemetry-receiver", + "fontFamily": "JetBrains Mono", + "fontSize": 11.5, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "E6Ij9", + "name": "Article Next Link", + "width": "fill_container", + "stroke": "$border/border", + "strokeWidth": { + "top": 1 + }, + "strokeAlignment": "inner", + "strokeLinejoin": "round", + "padding": [ + 10, + 0, + 0, + 0 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "tGh72", + "name": "Next Link Text", + "layout": "vertical", + "gap": 2, + "children": [ + { + "type": "text", + "id": "n7Wk4D", + "name": "Next Link Eyebrow", + "fill": "$field/placeholder", + "content": "NEXT GUIDE", + "fontFamily": "Geist", + "fontSize": 10, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "puiav", + "name": "Next Link Title", + "fill": "$foreground/foreground", + "content": "Modules & Sources", + "fontFamily": "JetBrains Mono", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "icon", + "id": "w3b2s", + "name": "Next Link Icon", + "width": 15, + "height": 15, + "icon": "arrow-right", + "library": "lucide", + "fill": "$muted" + } + ] + } + ] + }, + { + "type": "frame", + "id": "YtKMy", + "name": "Docs Page Aside", + "width": 250, + "layout": "vertical", + "gap": 16, + "children": [ + { + "type": "frame", + "id": "xldKp", + "name": "Docs Table of Contents", + "width": "fill_container", + "fill": "$surface/secondary", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 10, + "padding": 16, + "children": [ + { + "type": "text", + "id": "zC3Vk", + "name": "TOC Label", + "fill": "$field/placeholder", + "content": "ON THIS PAGE", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.7 + }, + { + "type": "frame", + "id": "uRE6y", + "name": "TOC Row 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "is2JC", + "name": "TOC Icon 0", + "width": 12, + "height": 12, + "icon": "hash", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "j5iQg", + "name": "TOC Text 0", + "fill": "$foreground/foreground", + "content": "Prerequisites", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "RX9pE", + "name": "TOC Row 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "L9Nhsn", + "name": "TOC Icon 1", + "width": 12, + "height": 12, + "icon": "hash", + "library": "lucide", + "fill": "$field/placeholder" + }, + { + "type": "text", + "id": "WuCS6", + "name": "TOC Text 1", + "fill": "$muted", + "content": "Deploy", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "X6wqe", + "name": "TOC Row 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "G5UjH1", + "name": "TOC Icon 2", + "width": 12, + "height": 12, + "icon": "hash", + "library": "lucide", + "fill": "$field/placeholder" + }, + { + "type": "text", + "id": "s0q1D", + "name": "TOC Text 2", + "fill": "$muted", + "content": "Verify", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "rectangle", + "id": "d8x3dn", + "name": "TOC Divider", + "fill": "$border/border", + "width": "fill_container", + "height": 1 + }, + { + "type": "text", + "id": "hDb6b", + "name": "Coverage Label", + "fill": "$field/placeholder", + "content": "COVERS", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.7 + }, + { + "type": "frame", + "id": "n7BbCj", + "name": "Coverage Row 0", + "width": "fill_container", + "gap": 7, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "atDQk", + "name": "Coverage Icon 0", + "width": 12, + "height": 12, + "icon": "book-open", + "library": "lucide", + "fill": "$field/placeholder" + }, + { + "type": "text", + "id": "v04wFm", + "name": "Coverage Text 0", + "fill": "$muted", + "content": "Receiver", + "fontFamily": "Geist", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "TEQ3A", + "name": "Coverage Row 1", + "width": "fill_container", + "gap": 7, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "j5Bkk", + "name": "Coverage Icon 1", + "width": 12, + "height": 12, + "icon": "book-open", + "library": "lucide", + "fill": "$field/placeholder" + }, + { + "type": "text", + "id": "irqCf", + "name": "Coverage Text 1", + "fill": "$muted", + "content": "Ingress", + "fontFamily": "Geist", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "un0Cc", + "name": "Coverage Row 2", + "width": "fill_container", + "gap": 7, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "X6NpwX", + "name": "Coverage Icon 2", + "width": 12, + "height": 12, + "icon": "book-open", + "library": "lucide", + "fill": "$field/placeholder" + }, + { + "type": "text", + "id": "qwZP3", + "name": "Coverage Text 2", + "fill": "$muted", + "content": "NetworkPolicy", + "fontFamily": "Geist", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "ADQQC", + "name": "Edit Page Card", + "width": "fill_container", + "fill": "$background/background", + "cornerRadius": "$radius/3xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 6, + "padding": 14, + "children": [ + { + "type": "text", + "id": "x6nVz", + "name": "Edit Page Title", + "fill": "$foreground/foreground", + "content": "Improve this page", + "fontFamily": "JetBrains Mono", + "fontSize": 12, + "fontWeight": "600" + }, + { + "type": "text", + "id": "FPsz5", + "name": "Edit Page Body", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Found a gap? Open a docs issue or suggest an edit on GitHub.", + "lineHeight": 1.4, + "fontFamily": "Geist", + "fontSize": 11.5, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "CVoqN", + "name": "Edit Page Link", + "gap": 6, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "t8Vni", + "name": "Edit Page Link Text", + "fill": "$accent/soft-foreground", + "content": "Edit this page", + "fontFamily": "Geist", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "icon", + "id": "qN32s", + "name": "Edit Page Link Icon", + "width": 12, + "height": 12, + "icon": "external-link", + "library": "lucide", + "fill": "$accent/accent" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] +} diff --git a/website-export/json/zeM79.json b/website-export/json/zeM79.json index b3d9047..f223afe 100644 --- a/website-export/json/zeM79.json +++ b/website-export/json/zeM79.json @@ -9,7 +9,7 @@ }, "clip": true, "width": 1440, - "height": 900, + "height": 1060, "fill": "$background/background", "children": [ { @@ -478,6 +478,154 @@ } ] }, + { + "type": "frame", + "id": "bnwpq", + "name": "Guide Section 2", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "VIhxu", + "name": "Section Title 2", + "fill": "$foreground/foreground", + "content": "Disable usage telemetry", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "Rksuv", + "name": "Section Body 2", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "New installs report to telemetry.gameplane.net; turn it off at install time so an offline cluster never retries.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "v2NVGT", + "name": "Section List 2", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "u14sh", + "name": "Section 2 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "V8cY0g", + "name": "Section 2 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "Bz19Z", + "name": "Section 2 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Set api.telemetry.enabled=false in values-offline.yaml: no notice, switches unavailable.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "bHFcS", + "name": "Section 2 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "R8Kyy", + "name": "Section 2 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "J8bI0", + "name": "Section 2 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Or enable the bundled receiver (api.telemetry.receiver.enabled=true) to keep figures in-cluster.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "fbmRB", + "name": "Section 2 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "CkeBb", + "name": "Section 2 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "dbabW", + "name": "Section 2 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Or point api.telemetry.endpoint at an internal receiver.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, { "type": "frame", "id": "A0wSAt", diff --git a/website-export/screenshots/B39hL.png b/website-export/screenshots/B39hL.png index ac649af..3fec5f6 100644 Binary files a/website-export/screenshots/B39hL.png and b/website-export/screenshots/B39hL.png differ diff --git a/website-export/screenshots/IGuE6.png b/website-export/screenshots/IGuE6.png index b117dff..379823a 100644 Binary files a/website-export/screenshots/IGuE6.png and b/website-export/screenshots/IGuE6.png differ diff --git a/website-export/screenshots/JjbY2.png b/website-export/screenshots/JjbY2.png index 54a47cc..08773d3 100644 Binary files a/website-export/screenshots/JjbY2.png and b/website-export/screenshots/JjbY2.png differ diff --git a/website-export/screenshots/K6tq5Z.png b/website-export/screenshots/K6tq5Z.png new file mode 100644 index 0000000..29049ae Binary files /dev/null and b/website-export/screenshots/K6tq5Z.png differ diff --git a/website-export/screenshots/cpCjN.png b/website-export/screenshots/cpCjN.png index ab11e67..83aee3f 100644 Binary files a/website-export/screenshots/cpCjN.png and b/website-export/screenshots/cpCjN.png differ diff --git a/website-export/screenshots/ei1qC.png b/website-export/screenshots/ei1qC.png index e5d8d80..144c548 100644 Binary files a/website-export/screenshots/ei1qC.png and b/website-export/screenshots/ei1qC.png differ diff --git a/website-export/screenshots/gnZrl.png b/website-export/screenshots/gnZrl.png index 2efe69c..275feb0 100644 Binary files a/website-export/screenshots/gnZrl.png and b/website-export/screenshots/gnZrl.png differ diff --git a/website-export/screenshots/hnTHJ.png b/website-export/screenshots/hnTHJ.png index 863e7d5..8c46783 100644 Binary files a/website-export/screenshots/hnTHJ.png and b/website-export/screenshots/hnTHJ.png differ diff --git a/website-export/screenshots/kTRsn.png b/website-export/screenshots/kTRsn.png index 7b1aa10..45e0836 100644 Binary files a/website-export/screenshots/kTRsn.png and b/website-export/screenshots/kTRsn.png differ diff --git a/website-export/screenshots/s0Q7Lf.png b/website-export/screenshots/s0Q7Lf.png new file mode 100644 index 0000000..09e0e82 Binary files /dev/null and b/website-export/screenshots/s0Q7Lf.png differ diff --git a/website-export/screenshots/tfxmL.png b/website-export/screenshots/tfxmL.png index 9e53b87..53db459 100644 Binary files a/website-export/screenshots/tfxmL.png and b/website-export/screenshots/tfxmL.png differ diff --git a/website-export/screenshots/vh8hz.png b/website-export/screenshots/vh8hz.png index 73f89b3..fa4d0f7 100644 Binary files a/website-export/screenshots/vh8hz.png and b/website-export/screenshots/vh8hz.png differ diff --git a/website-export/screenshots/zeM79.png b/website-export/screenshots/zeM79.png index f11a21f..a598543 100644 Binary files a/website-export/screenshots/zeM79.png and b/website-export/screenshots/zeM79.png differ diff --git a/website.pen b/website.pen index 1f09e73..3d0aecd 100644 --- a/website.pen +++ b/website.pen @@ -16001,6 +16001,15 @@ "fontSize": 13, "fontWeight": "normal" }, + { + "type": "text", + "id": "i8tUo", + "fill": "$muted", + "content": "Telemetry", + "fontFamily": "$typography/font-sans", + "fontSize": 13, + "fontWeight": "normal" + }, { "type": "text", "id": "yNiWc", @@ -32628,7 +32637,7 @@ }, "clip": true, "width": 1440, - "height": 900, + "height": 1100, "fill": "$background/background", "children": [ { @@ -34094,6 +34103,514 @@ } ] }, + { + "type": "frame", + "id": "tRi5P", + "name": "Reference Block 2", + "width": "fill_container", + "layout": "vertical", + "gap": 7, + "children": [ + { + "type": "text", + "id": "ve1hm", + "name": "Reference Block Title 2", + "fill": "$foreground/foreground", + "content": "Telemetry", + "fontFamily": "JetBrains Mono", + "fontSize": 14, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "GJJ49", + "name": "Reference Table 2", + "clip": true, + "width": "fill_container", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "IXzky", + "name": "Reference Table Header 2", + "width": "fill_container", + "height": 32, + "fill": "$surface/surface", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "QrGUl", + "name": "Header 2 Cell 0", + "width": 270, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "FxMCK", + "name": "Header 2 Text 0", + "fill": "$field/placeholder", + "content": "KEY", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.5 + } + ] + }, + { + "type": "frame", + "id": "T3N3pu", + "name": "Header 2 Cell 1", + "width": 130, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "anzma", + "name": "Header 2 Text 1", + "fill": "$field/placeholder", + "content": "TYPE", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.5 + } + ] + }, + { + "type": "frame", + "id": "hbiyO", + "name": "Header 2 Cell 2", + "width": 150, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "o6NhB", + "name": "Header 2 Text 2", + "fill": "$field/placeholder", + "content": "DEFAULT", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.5 + } + ] + }, + { + "type": "frame", + "id": "bMBLB", + "name": "Header 2 Cell 3", + "width": "fill_container", + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "BlL2h", + "name": "Header 2 Text 3", + "fill": "$field/placeholder", + "content": "DESCRIPTION", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.5 + } + ] + } + ] + }, + { + "type": "frame", + "id": "uOCEr", + "name": "Reference 2 Row 0", + "width": "fill_container", + "height": 38, + "fill": "$background/background", + "stroke": "$separator/separator", + "strokeWidth": { + "top": 1 + }, + "strokeAlignment": "inner", + "strokeLinejoin": "round", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "CPSh7", + "name": "Reference 2 Row 0 Cell 0", + "width": 270, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "q6LPo", + "name": "Reference 2 Row 0 Text 0", + "fill": "$accent/soft-foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "api.telemetry.enabled", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "utLKh", + "name": "Reference 2 Row 0 Cell 1", + "width": 130, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "Jibby", + "name": "Reference 2 Row 0 Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "boolean", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "fa2Q9", + "name": "Reference 2 Row 0 Cell 2", + "width": 150, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "n2sEF0", + "name": "Reference 2 Row 0 Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "true", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "P1XviT", + "name": "Reference 2 Row 0 Cell 3", + "width": "fill_container", + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "KIoHQ", + "name": "Reference 2 Row 0 Text 3", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Hard on/off; false never sends and shows no first-login notice.", + "fontFamily": "Geist", + "fontSize": 11, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "Dh5IF", + "name": "Reference 2 Row 1", + "width": "fill_container", + "height": 38, + "fill": "$surface/secondary", + "stroke": "$separator/separator", + "strokeWidth": { + "top": 1 + }, + "strokeAlignment": "inner", + "strokeLinejoin": "round", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "iiEeS", + "name": "Reference 2 Row 1 Cell 0", + "width": 270, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "EfC1J", + "name": "Reference 2 Row 1 Text 0", + "fill": "$accent/soft-foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "api.telemetry.endpoint", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "IQOvT", + "name": "Reference 2 Row 1 Cell 1", + "width": 130, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "D1ap9", + "name": "Reference 2 Row 1 Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "url", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "ElCtX", + "name": "Reference 2 Row 1 Cell 2", + "width": 150, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "ar0Zh", + "name": "Reference 2 Row 1 Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "project provider", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "qV0zR", + "name": "Reference 2 Row 1 Cell 3", + "width": "fill_container", + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "MAoMo", + "name": "Reference 2 Row 1 Text 3", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Where reports go; set your own receiver URL to replace the default.", + "fontFamily": "Geist", + "fontSize": 11, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "RnTXg", + "name": "Reference 2 Row 2", + "width": "fill_container", + "height": 38, + "fill": "$background/background", + "stroke": "$separator/separator", + "strokeWidth": { + "top": 1 + }, + "strokeAlignment": "inner", + "strokeLinejoin": "round", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "h2N06B", + "name": "Reference 2 Row 2 Cell 0", + "width": 270, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "tVdo7", + "name": "Reference 2 Row 2 Text 0", + "fill": "$accent/soft-foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "api.telemetry.receiver.enabled", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "fOC6z", + "name": "Reference 2 Row 2 Cell 1", + "width": 130, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "EFsxL", + "name": "Reference 2 Row 2 Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "boolean", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "Cl31u", + "name": "Reference 2 Row 2 Cell 2", + "width": 150, + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "wBDVq", + "name": "Reference 2 Row 2 Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "false", + "fontFamily": "JetBrains Mono", + "fontSize": 10.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "k6P2k", + "name": "Reference 2 Row 2 Cell 3", + "width": "fill_container", + "height": "fill_container", + "padding": [ + 0, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "tMUKA", + "name": "Reference 2 Row 2 Text 3", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Deploy the bundled receiver; reports stay inside the cluster.", + "fontFamily": "Geist", + "fontSize": 11, + "fontWeight": "normal" + } + ] + } + ] + } + ] + } + ] + }, { "type": "frame", "id": "uKwVB", @@ -43833,7 +44350,7 @@ }, "clip": true, "width": 1440, - "height": 900, + "height": 1060, "fill": "$background/background", "children": [ { @@ -44302,6 +44819,154 @@ } ] }, + { + "type": "frame", + "id": "bnwpq", + "name": "Guide Section 2", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "VIhxu", + "name": "Section Title 2", + "fill": "$foreground/foreground", + "content": "Disable usage telemetry", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "Rksuv", + "name": "Section Body 2", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "New installs report to telemetry.gameplane.net; turn it off at install time so an offline cluster never retries.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "v2NVGT", + "name": "Section List 2", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "u14sh", + "name": "Section 2 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "V8cY0g", + "name": "Section 2 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "Bz19Z", + "name": "Section 2 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Set api.telemetry.enabled=false in values-offline.yaml: no notice, switches unavailable.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "bHFcS", + "name": "Section 2 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "R8Kyy", + "name": "Section 2 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "J8bI0", + "name": "Section 2 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Or enable the bundled receiver (api.telemetry.receiver.enabled=true) to keep figures in-cluster.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "fbmRB", + "name": "Section 2 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "CkeBb", + "name": "Section 2 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "dbabW", + "name": "Section 2 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Or point api.telemetry.endpoint at an internal receiver.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, { "type": "frame", "id": "A0wSAt", @@ -61835,7 +62500,7 @@ "fill": "$muted", "textGrowth": "fixed-width", "width": "fill_container", - "content": "Maintain instance identity and defaults, make an explicit telemetry choice, and capture exact build data for support.", + "content": "Maintain instance identity and defaults, review the telemetry tiers and opt-out, and capture exact build data for support.", "lineHeight": 1.45, "fontFamily": "Geist", "fontSize": 15, @@ -62097,7 +62762,7 @@ "fill": "$muted", "textGrowth": "fixed-width", "width": "fill_container", - "content": "Usage telemetry is an explicit choice and is not a substitute for operational metrics and logs.", + "content": "On by default for new installs; reports go to the project's provider unless an operator disables or redirects them.", "lineHeight": 1.45, "fontFamily": "Geist", "fontSize": 13, @@ -62145,7 +62810,7 @@ "fill": "$default/foreground", "textGrowth": "fixed-width", "width": "fill_container", - "content": "The current promise excludes server names, players, and identifying data.", + "content": "Basic sends version and two counts; extended adds coarse environment and usage bands.", "fontFamily": "Geist", "fontSize": 12.5, "fontWeight": "normal" @@ -62177,7 +62842,7 @@ "fill": "$default/foreground", "textGrowth": "fixed-width", "width": "fill_container", - "content": "Document any required organizational privacy review.", + "content": "Set api.telemetry.enabled=false for a hard off; api.telemetry.endpoint redirects reports.", "fontFamily": "Geist", "fontSize": 12.5, "fontWeight": "normal" @@ -62209,7 +62874,7 @@ "fill": "$default/foreground", "textGrowth": "fixed-width", "width": "fill_container", - "content": "Recheck the saved choice after upgrades.", + "content": "Installs that never saved a choice stay off after an upgrade; recheck the setting.", "fontFamily": "Geist", "fontSize": 12.5, "fontWeight": "normal" @@ -62291,7 +62956,7 @@ "id": "f3i2WR", "name": "Quick Reference Line 2", "fill": "$foreground/foreground", - "content": "02 Explicit telemetry choice; operational monitoring remains separate", + "content": "02 Telemetry tiers chosen on purpose (or disabled at install); monitoring stays separate", "fontFamily": "JetBrains Mono", "fontSize": 11.5, "fontWeight": "normal" @@ -62352,7 +63017,7 @@ "id": "biGQY", "name": "Next Link Title", "fill": "$foreground/foreground", - "content": "Modules & Sources", + "content": "Telemetry provider on Kubernetes", "fontFamily": "JetBrains Mono", "fontSize": 13, "fontWeight": "500" @@ -96793,6 +97458,16 @@ "fontSize": 13, "fontWeight": "normal" }, + { + "type": "text", + "id": "A07NYu", + "name": "Telemetry", + "fill": "$muted", + "content": "Telemetry", + "fontFamily": "$typography/font-sans", + "fontSize": 13, + "fontWeight": "normal" + }, { "type": "text", "id": "XUlGh", @@ -109536,6 +110211,1727 @@ ] } ] + }, + { + "type": "frame", + "id": "s0Q7Lf", + "x": 0, + "y": 119308, + "name": "Screen/Docs — Telemetry Provider on Kubernetes", + "theme": { + "semantic": "dark" + }, + "clip": true, + "width": 1440, + "height": 900, + "fill": "$background/background", + "children": [ + { + "id": "QKRsx", + "type": "ref", + "ref": "K2Rt4H", + "height": "fill_container", + "name": "DocsSidebar/Expanded", + "width": 280 + }, + { + "type": "frame", + "id": "DROu9", + "name": "Docs Main", + "width": "fill_container", + "height": "fill_container", + "fill": "$background/background", + "layout": "vertical", + "children": [ + { + "id": "bO17d", + "type": "ref", + "ref": "SOdlr", + "name": "Docs Top Bar", + "width": "fill_container", + "descendants": { + "NImey": { + "content": "Platform" + }, + "ikbi6": { + "content": "Telemetry Provider" + } + } + }, + { + "type": "frame", + "id": "S5WmgI", + "name": "Docs Article Body", + "clip": true, + "width": "fill_container", + "height": "fill_container", + "gap": 32, + "padding": 32, + "children": [ + { + "type": "frame", + "id": "I8IIud", + "name": "Docs Article", + "width": 780, + "layout": "vertical", + "gap": 14, + "children": [ + { + "type": "text", + "id": "blRMz", + "name": "Article Eyebrow", + "fill": "$accent/accent", + "content": "OPERATIONS", + "fontFamily": "JetBrains Mono", + "fontSize": 11, + "fontWeight": "600", + "letterSpacing": 0.8 + }, + { + "type": "text", + "id": "kFlid", + "name": "Article Title", + "fill": "$foreground/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Run a telemetry provider on Kubernetes", + "lineHeight": 1.1, + "fontFamily": "JetBrains Mono", + "fontSize": 30, + "fontWeight": "700" + }, + { + "type": "text", + "id": "Dtwec", + "name": "Article Lead", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Deploy a standalone Gameplane telemetry receiver with TLS, a private dashboard and proof-of-work, using plain manifests.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 15, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "Lzi4R", + "name": "Article Metadata", + "gap": 8, + "alignItems": "center", + "children": [ + { + "id": "Bbhc7", + "type": "ref", + "ref": "NZPtq", + "name": "Meta Chip 0", + "descendants": { + "NLG8t": { + "content": "ADMIN GUIDE" + } + } + }, + { + "id": "I6iGr", + "type": "ref", + "ref": "EbSsA", + "name": "Meta Chip 1", + "descendants": { + "yb6zz": { + "content": "v0.3" + } + } + }, + { + "id": "uv7WH", + "type": "ref", + "ref": "EbSsA", + "name": "Meta Chip 2", + "descendants": { + "yb6zz": { + "content": "10 MIN" + } + } + } + ] + }, + { + "type": "frame", + "id": "c0ABw", + "name": "Article Callout", + "width": "fill_container", + "fill": "$accent/soft", + "cornerRadius": "$radius/xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "gap": 10, + "padding": [ + 10, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "ThyU7", + "name": "Article Callout Icon", + "width": 16, + "height": 16, + "icon": "shield-alert", + "library": "lucide", + "fill": "$accent/soft-foreground" + }, + { + "type": "text", + "id": "w0dKI", + "name": "Article Callout Text", + "fill": "$accent/soft-foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Most operators do not need this: installs report to the project's provider by default.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "s2Zsb4", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "VN4Wg", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Prerequisites", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "KCVXt", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Run it in its own namespace, gameplane-telemetry, on k3s or any cluster with Traefik, cert-manager and a Cloudflare zone.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "deZ4U", + "name": "Section List 1", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "sknwg", + "name": "Section 1 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "Pkqup", + "name": "Section 1 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "ebGaK", + "name": "Section 1 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Traefik trusts Cloudflare's forwarded headers (forwardedHeaders.trustedIPs).", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "dhggu", + "name": "Section 1 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "joqYN", + "name": "Section 1 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "I0dYh", + "name": "Section 1 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "cert-manager issues the certificate through a Cloudflare DNS-01 challenge.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "NNQms", + "name": "Section 1 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "danEX", + "name": "Section 1 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "T1x0C", + "name": "Section 1 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "A CNI that enforces NetworkPolicies (the kube-router that ships with k3s does).", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "VlhLM", + "name": "Guide Section 2", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "VJHMC", + "name": "Section Title 2", + "fill": "$foreground/foreground", + "content": "Deploy the receiver", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "F8yR0", + "name": "Section Body 2", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Secrets and trusted proxies, certificate issuer, then the receiver, Service, Ingress and NetworkPolicy.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "hbNTK", + "name": "Section List 2", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "f3nnPH", + "name": "Section 2 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "IOTII", + "name": "Section 2 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "j5ScU", + "name": "Section 2 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "One replica with Recreate; the SQLite database lives on a PVC at /data.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "htOVS", + "name": "Section 2 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "P717K2", + "name": "Section 2 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "Q20MTv", + "name": "Section 2 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The Ingress publishes only the public listener, never the dashboard on :8081.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "WVTQx", + "name": "Section 2 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "thS2Z", + "name": "Section 2 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "ulkKj", + "name": "Section 2 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "NetworkPolicy: 8080 from Traefik, 8081 from monitoring, no egress.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "FyxIG", + "name": "Guide Section 3", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "g6nDx9", + "name": "Section Title 3", + "fill": "$foreground/foreground", + "content": "Verify and operate", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "FlPrm", + "name": "Section Body 3", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Check readiness, the proof-of-work challenge and the client address; open the dashboard over port-forward.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "mOpLG", + "name": "Quick Reference", + "width": "fill_container", + "fill": "$surface/tertiary", + "cornerRadius": "$radius/xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 3, + "padding": 12, + "children": [ + { + "type": "text", + "id": "F52Z5", + "name": "Quick Reference Label", + "fill": "$accent/accent", + "content": "PROVIDER RUNBOOK", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.6 + }, + { + "type": "text", + "id": "MJqJo", + "name": "Quick Reference Line 1", + "fill": "$foreground/foreground", + "content": "01 kubectl apply -f telemetry-provider.yaml", + "fontFamily": "JetBrains Mono", + "fontSize": 11.5, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "tOURa", + "name": "Quick Reference Line 2", + "fill": "$foreground/foreground", + "content": "02 kubectl -n gameplane-telemetry port-forward svc/telemetry-receiver 8081:8081", + "fontFamily": "JetBrains Mono", + "fontSize": 11.5, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "wZhrZ", + "name": "Quick Reference Line 3", + "fill": "$foreground/foreground", + "content": "03 kubectl -n gameplane-telemetry rollout restart deploy/telemetry-receiver", + "fontFamily": "JetBrains Mono", + "fontSize": 11.5, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "E6Ij9", + "name": "Article Next Link", + "width": "fill_container", + "stroke": "$border/border", + "strokeWidth": { + "top": 1 + }, + "strokeAlignment": "inner", + "strokeLinejoin": "round", + "padding": [ + 10, + 0, + 0, + 0 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "tGh72", + "name": "Next Link Text", + "layout": "vertical", + "gap": 2, + "children": [ + { + "type": "text", + "id": "n7Wk4D", + "name": "Next Link Eyebrow", + "fill": "$field/placeholder", + "content": "NEXT GUIDE", + "fontFamily": "Geist", + "fontSize": 10, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "puiav", + "name": "Next Link Title", + "fill": "$foreground/foreground", + "content": "Modules & Sources", + "fontFamily": "JetBrains Mono", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "icon", + "id": "w3b2s", + "name": "Next Link Icon", + "width": 15, + "height": 15, + "icon": "arrow-right", + "library": "lucide", + "fill": "$muted" + } + ] + } + ] + }, + { + "type": "frame", + "id": "YtKMy", + "name": "Docs Page Aside", + "width": 250, + "layout": "vertical", + "gap": 16, + "children": [ + { + "type": "frame", + "id": "xldKp", + "name": "Docs Table of Contents", + "width": "fill_container", + "fill": "$surface/secondary", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 10, + "padding": 16, + "children": [ + { + "type": "text", + "id": "zC3Vk", + "name": "TOC Label", + "fill": "$field/placeholder", + "content": "ON THIS PAGE", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.7 + }, + { + "type": "frame", + "id": "uRE6y", + "name": "TOC Row 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "is2JC", + "name": "TOC Icon 0", + "width": 12, + "height": 12, + "icon": "hash", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "j5iQg", + "name": "TOC Text 0", + "fill": "$foreground/foreground", + "content": "Prerequisites", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "RX9pE", + "name": "TOC Row 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "L9Nhsn", + "name": "TOC Icon 1", + "width": 12, + "height": 12, + "icon": "hash", + "library": "lucide", + "fill": "$field/placeholder" + }, + { + "type": "text", + "id": "WuCS6", + "name": "TOC Text 1", + "fill": "$muted", + "content": "Deploy", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "X6wqe", + "name": "TOC Row 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "G5UjH1", + "name": "TOC Icon 2", + "width": 12, + "height": 12, + "icon": "hash", + "library": "lucide", + "fill": "$field/placeholder" + }, + { + "type": "text", + "id": "s0q1D", + "name": "TOC Text 2", + "fill": "$muted", + "content": "Verify", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "rectangle", + "id": "d8x3dn", + "name": "TOC Divider", + "fill": "$border/border", + "width": "fill_container", + "height": 1 + }, + { + "type": "text", + "id": "hDb6b", + "name": "Coverage Label", + "fill": "$field/placeholder", + "content": "COVERS", + "fontFamily": "JetBrains Mono", + "fontSize": 9, + "fontWeight": "600", + "letterSpacing": 0.7 + }, + { + "type": "frame", + "id": "n7BbCj", + "name": "Coverage Row 0", + "width": "fill_container", + "gap": 7, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "atDQk", + "name": "Coverage Icon 0", + "width": 12, + "height": 12, + "icon": "book-open", + "library": "lucide", + "fill": "$field/placeholder" + }, + { + "type": "text", + "id": "v04wFm", + "name": "Coverage Text 0", + "fill": "$muted", + "content": "Receiver", + "fontFamily": "Geist", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "TEQ3A", + "name": "Coverage Row 1", + "width": "fill_container", + "gap": 7, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "j5Bkk", + "name": "Coverage Icon 1", + "width": 12, + "height": 12, + "icon": "book-open", + "library": "lucide", + "fill": "$field/placeholder" + }, + { + "type": "text", + "id": "irqCf", + "name": "Coverage Text 1", + "fill": "$muted", + "content": "Ingress", + "fontFamily": "Geist", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "un0Cc", + "name": "Coverage Row 2", + "width": "fill_container", + "gap": 7, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "X6NpwX", + "name": "Coverage Icon 2", + "width": 12, + "height": 12, + "icon": "book-open", + "library": "lucide", + "fill": "$field/placeholder" + }, + { + "type": "text", + "id": "qwZP3", + "name": "Coverage Text 2", + "fill": "$muted", + "content": "NetworkPolicy", + "fontFamily": "Geist", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "ADQQC", + "name": "Edit Page Card", + "width": "fill_container", + "fill": "$background/background", + "cornerRadius": "$radius/3xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 6, + "padding": 14, + "children": [ + { + "type": "text", + "id": "x6nVz", + "name": "Edit Page Title", + "fill": "$foreground/foreground", + "content": "Improve this page", + "fontFamily": "JetBrains Mono", + "fontSize": 12, + "fontWeight": "600" + }, + { + "type": "text", + "id": "FPsz5", + "name": "Edit Page Body", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Found a gap? Open a docs issue or suggest an edit on GitHub.", + "lineHeight": 1.4, + "fontFamily": "Geist", + "fontSize": 11.5, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "CVoqN", + "name": "Edit Page Link", + "gap": 6, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "t8Vni", + "name": "Edit Page Link Text", + "fill": "$accent/soft-foreground", + "content": "Edit this page", + "fontFamily": "Geist", + "fontSize": 12, + "fontWeight": "500" + }, + { + "type": "icon", + "id": "qN32s", + "name": "Edit Page Link Icon", + "width": 12, + "height": 12, + "icon": "external-link", + "library": "lucide", + "fill": "$accent/accent" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "K6tq5Z", + "x": 0, + "y": 120468, + "name": "Screen/Telemetry Statement", + "theme": { + "semantic": "dark" + }, + "width": 1440, + "fill": "$background/background", + "layout": "vertical", + "children": [ + { + "id": "PdJ8e", + "type": "ref", + "ref": "Qczsa", + "name": "Nav", + "width": "fill_container" + }, + { + "type": "frame", + "id": "OUmXG", + "name": "CompareBody", + "width": "fill_container", + "fill": "$background/background", + "layout": "vertical", + "gap": 48, + "padding": [ + 80, + 80, + 96, + 80 + ], + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "qo6MM", + "name": "header", + "width": "fill_container", + "layout": "vertical", + "gap": 12, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "a8t4F", + "fill": "$accent/accent", + "content": "TELEMETRY", + "textAlign": "center", + "fontFamily": "$typography/font-mono", + "fontSize": 12, + "fontWeight": "600", + "letterSpacing": 1 + }, + { + "type": "text", + "id": "slZsE", + "fill": "$foreground/foreground", + "textGrowth": "fixed-width", + "width": 760, + "content": "Telemetry data-handling statement", + "textAlign": "center", + "fontFamily": "$typography/font-mono", + "fontSize": 34, + "fontWeight": "700" + }, + { + "type": "text", + "id": "Yh3u2", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": 760, + "content": "Last updated 2026-10-07.", + "textAlign": "center", + "fontFamily": "$typography/font-sans", + "fontSize": 16, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "GTNTv", + "name": "Statement Article", + "width": 780, + "layout": "vertical", + "gap": 14, + "children": [ + { + "type": "frame", + "id": "cIqhi", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "vDbJD", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Who operates it", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "L7CpT", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "The project maintainers run the default provider at telemetry.gameplane.net; anyone can run their own. This statement covers only the project's.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "FVk7Z", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "b8KAG1", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "What is sent", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "SU5Ke", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Two tiers, about once a day, only while an admin leaves them on.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "Q183g", + "name": "Section List 1", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "dpiXu", + "name": "Section 1 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "PqLHX", + "name": "Section 1 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "IhwQy", + "name": "Section 1 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Basic: version, servers (GameServer count) and templates (GameTemplate count).", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "x9o0L", + "name": "Section 1 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "OH7vg", + "name": "Section 1 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "ep1Ap", + "name": "Section 1 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Extended adds: random install ID, Kubernetes minor, distribution, architectures, node-count band.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "S4RzSN", + "name": "Section 1 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "L79w87", + "name": "Section 1 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "NC4AK", + "name": "Section 1 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Also per-module server counts, feature flags and bands, database kind, UI language, public key, send time.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "U5KLl", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "s9Soql", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Signing and the install ID", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "Qb50x", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Extended reports are signed (Ed25519) so nobody can report under another install's ID. The ID is pseudonymous; an admin can reset it, and it is deleted when extended is turned off.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "y2Woc", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "m5x3Q", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "What is never collected", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "A4Dzf", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Server names, namespaces, hostnames, player data, custom module names, free text, or any cluster, network or user address. Raw reports and source addresses are not stored.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "nFcmz", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "mlrJf", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "What the provider stores", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "d1jyC", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Daily aggregates, activity records and a total-reports counter.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "uiOWJ", + "name": "Section List 1", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "s2dHPF", + "name": "Section 1 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "S4xx2", + "name": "Section 1 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "YLcxz", + "name": "Section 1 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Daily aggregates: counts by version, fleet-size band and category, never linked to an install ID.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "P1eejb", + "name": "Section 1 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "S7sTv6", + "name": "Section 1 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "lnrR1", + "name": "Section 1 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Activity records: keyed hash of the install ID, key fingerprint, first/last seen, last version.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "cB3db", + "name": "Section 1 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "TSFRP", + "name": "Section 1 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "rvvnu", + "name": "Section 1 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Total-reports counter: a single number.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "t0qQ5B", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "NWxP8", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "How long", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "G5KyWM", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Aggregates 24 months; activity records 90 days after the last report; source addresses never written to disk.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "pYTx1", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "k3JsKp", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Abuse protection", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "O81l3", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Strict validation (16 KiB cap), per-source daily limit, proof-of-work that costs nothing in normal traffic, and a private token-protected dashboard.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "UoRma", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "a6pUwo", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Public summary", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "sKDfN", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "GET /v1/summary returns exactly five numbers; the detailed dashboard is private to the maintainers.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "GVGJA", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "vbCKO", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "How to opt out", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "DTDuT", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Notice before the first report, then separate switches in Admin Settings > Telemetry.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "epdW6", + "name": "Section List 1", + "width": "fill_container", + "fill": "$surface/surface", + "cornerRadius": "$radius/2xl", + "stroke": "$border/border", + "strokeWidth": 1, + "strokeAlignment": "inner", + "layout": "vertical", + "gap": 5, + "padding": [ + 8, + 10 + ], + "children": [ + { + "type": "frame", + "id": "x80Spm", + "name": "Section 1 Item 0", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "OYJHO", + "name": "Section 1 Item Icon 0", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "f4kxVu", + "name": "Section 1 Item Text 0", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "At first login: separate basic and extended switches; basic off turns extended off.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "p9saIX", + "name": "Section 1 Item 1", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "tz1ws", + "name": "Section 1 Item Icon 1", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "XulJR", + "name": "Section 1 Item Text 1", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "At install time: --set api.telemetry.enabled=false is a hard off with no notice.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "u1pPo", + "name": "Section 1 Item 2", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "icon", + "id": "hipxx", + "name": "Section 1 Item Icon 2", + "width": 13, + "height": 13, + "icon": "check", + "library": "lucide", + "fill": "$accent/accent" + }, + { + "type": "text", + "id": "KSniZ", + "name": "Section 1 Item Text 2", + "fill": "$default/foreground", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Custom provider: api.telemetry.endpoint=https://your-host/ingest replaces the project's.", + "fontFamily": "Geist", + "fontSize": 12.5, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "r5thm", + "name": "Guide Section 1", + "width": "fill_container", + "layout": "vertical", + "gap": 6, + "children": [ + { + "type": "text", + "id": "hHeyP", + "name": "Section Title 1", + "fill": "$foreground/foreground", + "content": "Questions and requests", + "fontFamily": "JetBrains Mono", + "fontSize": 17, + "fontWeight": "600" + }, + { + "type": "text", + "id": "u4JLM1", + "name": "Section Body 1", + "fill": "$muted", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Open an issue on GitHub; the maintainers operate the provider.", + "lineHeight": 1.45, + "fontFamily": "Geist", + "fontSize": 13, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "id": "CZkko", + "type": "ref", + "ref": "gnZrl", + "name": "Footer", + "width": "fill_container" + } + ] } ], "themes": {