BONGIGet early access

PRIVACY

Lustra Privacy Policy

Last updated: 2026-05-22.

Lustra is designed for customers who handle sensitive data. The product is on-premise — your reports, queries, and database credentials never leave your machine in the ordinary course of operation. This document describes the only ways anonymous data can leave your machine, both of which are opt-in.

Summary

SurfaceDefaultHow to enableHow to disable
Usage telemetryOffFirst-run wizard checkbox, or Settings → Privacy → Send anonymous usage dataSame toggle, any time
Crash reportsOffAsked per-incident when a crash happensClick "Skip" on the dialog

No persistent identifier exists. There is no user ID, no machine ID, no anonymous fingerprint, no MAC address, no disk serial, no IP-based correlation. Each app launch generates a fresh random session ID that is regenerated on the next launch — two events from the same machine on different days look like two different customers.

Full event list (usage telemetry)

When you opt in, the following events may be sent in batches every 60 seconds while the app is running:

EventWhat it tells usProperties (no PII)
app.start / app.exitApp lifecyclenone
report.createdA report was savedqueryCount, sheetCount
report.openedA report was loadedqueryCount
report.exportedA report was exportedformat (xlsx / pdf), rowCountBucket (0-1K, 1K-10K, …)
chart.insertedA chart was renderedchartType (bar / line / pie / …)
ai.query.sentAn AI request startedprovider (anthropic / openai / …)
ai.agent.completedAn AI request finishedprovider, durationBucket (0-100ms, 100ms-1s, …)
connection.createdA new database connection was addeddbEngine (postgres / mysql / mssql / …)
schedule.createdA scheduled job was creatednone
feature.usedA feature was usedfeatureName
error.encounteredA handled error firederrorCode only — NEVER the message or stack

Every event also carries:

  • appVersion — the Lustra semver currently running
  • osPlatform'win32' | 'darwin' | 'linux'
  • osRelease — major.minor only (e.g., '10.0' for Windows 10/11). The full build number is intentionally not sent.
  • sessionId — random UUID for the current app launch
  • timestamp — unix milliseconds at the moment of emit

What's never collected

Under any opt-in level, Lustra does not collect:

  • File paths
  • Report names, query names, field names, column names
  • Query text, SQL, formula expressions
  • Database connection strings, hostnames, credentials
  • Customer-identifying information (email, IP address, machine ID, MAC address, disk serial)
  • Any stable identifier that could be used to correlate events across app launches or machines

The technical enforcement of these rules lives in packages/core/src/telemetry/types.ts, which constrains event properties to primitive string | number | boolean values so future code changes can't accidentally smuggle a result row, a connection string, or a file path into the payload.

How to disable

  1. In the app: Settings → Privacy → "Send anonymous usage data" → toggle off. Any in-flight batch is dropped immediately; no new events are queued or sent.
  2. At install: leave the checkbox unchecked on the "Help improve Lustra" step of the first-run setup wizard. The default state is unchecked.
  3. Via configuration: set the environment variable LUSTRA_TELEMETRY_DISABLED=1 before launching the app. This forces network calls off regardless of the in-app toggle state (the toggle still appears in Settings; the network layer just doesn't honour it).

Crash reports

Crash reports are handled separately and are not governed by the usage-telemetry toggle. When the application crashes, you'll see a dialog with:

  • The exact stack trace that would be sent (scrollable, reviewable before sending)
  • A list of what's included (app version, OS, stack)
  • A list of what's not included (your data, queries, file paths)
  • A "Send crash report" button and a "Skip" button

The Send button is disabled for the first 2 seconds (or until you scroll the stack-trace pane, whichever comes first) so the report can't be sent before you've had a chance to look at it.

You consent per-incident. There is no global "always send crash reports" setting and we will not add one. Closing the dialog without clicking Send is equivalent to clicking Skip — no report leaves your machine.

What gets sent when you click Send:

  • Application version (e.g. 0.1.0)
  • Operating system label (e.g. Windows 10.0.26200)
  • The crash type (main-process exception or renderer-window crash)
  • The stack trace shown in the dialog

What is filtered out of the stack trace before sending:

  • Frames originating in node_modules/ (third-party libraries) — dropped to reduce noise
  • Console output and navigation history — these would otherwise attach as breadcrumbs; we disable that

What is never sent:

  • Your IP address — Sentry's sendDefaultPii: false is set, and Sentry's ingest endpoint does not record the source IP when this flag is set
  • Hostname, MAC address, disk serial, or any other machine identifier
  • File paths from your machine
  • Database credentials or query text
  • Report YAML, exported files, or any cell data
  • User-agent strings
  • Cached or persistent identifiers — every crash is a fresh disconnected report

Crash reports are sent to Sentry (organization bongi-io, project lustra-desktop) over HTTPS. The transport is built on @sentry/electron's main-process SDK with the Console and Breadcrumbs integrations explicitly disabled. Network failures during the send are silent — if the POST fails (no internet, Sentry outage), the report is dropped and the app exits without an error pop-up.

To disable crash reporting entirely: there is no in-app toggle, but you can set the environment variable LUSTRA_SENTRY_DISABLED=1 before launching Lustra. With that variable set, the SDK is never initialized; the crash dialog still appears (so you can see the stack trace yourself), but clicking Send is a no-op.

Data retention

Usage telemetry: 90 days, then deleted.

Crash reports: 1 year, then deleted.

These periods may be revisited as we learn how the data is actually useful, but the only direction we'll ever move them is shorter.

Server location

Telemetry events land at https://telemetry.bongi.io/ingest. Crash reports land at https://crashes.bongi.io/ingest. Both endpoints are hosted in the United States as of writing. EU residency is on the roadmap; if you have specific compliance requirements, please contact us before enabling telemetry.

Data deletion requests

Because there is no user-stable identifier, we cannot connect any event to a specific person or installation. There is therefore nothing to delete on a per-customer basis. If you've opted in and now want to revoke that consent, simply toggle telemetry off — no further data will be transmitted, and the events already sent are anonymised at the source.

For compliance enquiries: privacy@bongi.io.

Implementation references (for the technically curious)

  • Consent storage: packages/core/src/telemetry/consent.ts — atomic write to {configDir}/telemetry-consent.json, fails closed on any read/parse error.
  • Collector + batching: src/main/telemetry/collector.ts — 60-second batch, 1000-event queue cap, silent fail on network errors.
  • Network-disabled-by-default in dev: see the NETWORK_ENABLED constant in the collector — POSTs only happen when NODE_ENV === 'production'.
  • DI pattern: packages/core/src/telemetry/emitter.ts — core code emits through an interface, never imports main-process types.

Future-policy changes

If we materially change what's collected, the in-app first-run wizard step records decidedAppVersion. A future build can re-prompt customers whose recorded decision predates the policy boundary. We will never silently widen what's collected; any expansion requires a fresh explicit opt-in.