Files
ukmesh/docs/privacy.md
T
gadgethd b8628a78bf feat(telemetry+gdpr): shared client error capture, console.error hook, privacy page, retention jobs, packet_paths store
- clientErrors.ts: window.onerror/unhandledrejection for BOTH domains via main.tsx
  (was app-only in App.tsx); resource-failure classification; telemetry=off gate;
  console.error hook (kind warning) with terrain-tiles noise filter; page field
  now pathname-only (no query strings)
- PrivacyPage at /privacy linked from footer + cookie banner; docs/privacy.md LIA
- retention: packet_decryptions added to row-table retention targets; packets
  180d->30d in lifecycle policies; migration 050 schedules timescaledb retention
  jobs (packets 30d, node_status 180d, node_neighbor 7d) that never existed
- migration 050: packet_paths hypertable (content-stripped path store, no
  retention) + backfill of 2.56M path-bearing packets + ingest dual-write
2026-08-12 20:23:13 +00:00

69 lines
3.5 KiB
Markdown

# Privacy & data retention
Applies to ukmesh.com / app.ukmesh.com (MeshCore Analytics). UK GDPR + DPA 2018.
Contact: ukmesh@proton.me
## 1. Error diagnostics telemetry
**What is stored** (per event): kind (error/warning/unhandledrejection/crash),
truncated message (≤500 chars) and stack (≤4000 chars), page pathname only (no
query string), userAgent, HMAC-hashed source IP. No raw IPs, no account IDs,
no cookies, no localStorage in the telemetry path.
**Lawful basis — legitimate interest (Art 6(1)(f)).** Three-part test:
- **Purpose test:** operating a reliable public service requires knowing when
client-side failures occur; this telemetry has already root-caused real
production crashes (deck.gl/maplibre, worker-file MIME regressions).
- **Necessity test:** error capture cannot be tied to a logged-in account
(the site has no general auth), so pseudonymous event capture is the
minimum effective means; fields are bounded and truncated.
- **Balancing test:** data is pseudonymous (hashed IP, no identifiers), kept
30 days, rate-limited (10/min/IP) and sampled (20/hr/source), self-hosted
(no third-party processor → no DPA required), no profiling. Individual
impact is minimal; service reliability benefit is direct.
**Retention:** 30 days, enforced by the operational retention loop
(`DATA_LIFECYCLE_RETENTION_ENABLED=true` + `DATA_LIFECYCLE_RETENTION_TARGETS`).
**Erasure:** individuals cannot be mapped to rows; the retention job IS the
erasure mechanism (documented as such).
## 2. Mesh packet database
The service stores radio traffic observed on the MeshCore network.
| Data | Retained | Rationale |
|---|---|---|
| `packets` — message content + raw bytes + metadata | **30 days** (timescaledb retention job) | network diagnostics; content is not kept long-term |
| `packet_decryptions` — full decrypted messages | **30 days** (operational retention loop) | diagnostics only |
| `packet_paths` — path metadata (node IDs, timing, signal, hashes) | **indefinite, content-stripped** | raw pathing analytics is the product |
| `multibyte_path_facts`, `multihop_paths_weekly`, `path_*_priors` — derived path stats | indefinite | derived, pseudonymous |
| `packet_daily_stats` / `packet_hourly_stats` | indefinite | anonymous aggregates |
**Lawful basis — legitimate interest (Art 6(1)(f)).**
- **Purpose test:** operating and improving the network (pathing, coverage,
diagnostics) requires the packet data; the owner portal requires status data.
- **Necessity test:** content is deleted after 30 days; long-term retention is
limited to path metadata with no message content and no coordinates, which
is the minimum needed for pathing analytics.
- **Balancing test:** pseudonymous node identifiers only (linkable to an
individual solely when a node owner registers in the portal); no content in
long-lived tables; no individual profiling; disclosed in the privacy notice.
**Design rules (binding):**
- Path/long-lived tables NEVER gain `payload`, `raw_hex`, or coordinate
columns. Content-bearing tables always have a retention policy.
- Decryption outputs land only in short-retention tables (30 days).
- New derived tables get a lifecycle policy at creation.
- Erasure (Art 17): owner-portal-linked nodes are mappable — node-scoped
deletion procedure in the ops playbook (rows by src/rx node id across
packets, packet_paths, decryptions, path facts).
## 3. Cookies
LocalStorage-only choices (cookie consent, theme). No third-party cookies.
PECR does not apply to the mesh radio data (not a public electronic
communications network).