Pāriet uz saturu

Telemetry / Anonymous Usage Analytics

Statuss: Q14 Polish & Telemetry sprintā ieviests (2026-05-07) Privacy: Opt-in, GDPR atbilstošs, NEsatur PII


Kāpēc?

Bez telemetrijas mēs nezinām: - Kādus ekrānus lietotāji visbiežāk apmeklē - Kur viņi "stuck" (ilgs dwell, tad atstāj) - Kuru feature izmanto reti / nemaz - Vai jaunās UX izmaiņas patiesi uzlabo plūsmu

Q13 lauka beta atskaišu apkopošana ir anekdotiska. Telemetry dod kvantitatīvu datu plūsmu.


Privacy first

Kas TIEK sūtīts

  • event_name — fiksēts whitelist (sk. _ALLOWED_EVENT_NAMES)
  • screen — ekrāna nosaukums (MapScreen, InputScreen u.c.)
  • props — JSON ar event-specific datiem (no PII!)
  • app_version / app_build — versija un build SHA
  • platformandroid / ios / unknown
  • device_token — anonīms UUID (ca-nav-XXXXXXXX), kas ģenerēts pirmajā startā

Kas NETIEK sūtīts

  • ❌ GPS koordinātes
  • ❌ CA numuri (kuras īpašums)
  • ❌ Kadastra numuri
  • ❌ Lietotāja vārds, e-pasts, telefona numurs
  • ❌ Ierīces ID (Android ID, IDFA)
  • ❌ IP adrese (server log'os var parādīties, bet nav saglabāts event_log tabulā)
  • ❌ Faili / kontaktpersonas / kalendārs

Opt-in plūsma

  1. Lietotājs default: opt-in OFF, telemetrija nesūta neko
  2. Settings → Privātums → "Anonīma lietošanas analītika" toggle
  3. Pirmais opt-in: tooltip ar īsu skaidrojumu
  4. Lietotājs var jebkurā brīdī izslēgt — buffer iztīrīts uzreiz
  5. Lietotājs var pieprasīt visas vēstures dzēšanu — Settings → "Dzēst manu vēsturi" → DELETE /api/event/all

Server retention

90 dienas. Pēc tam events automātiski tiek dzēsti ar dienas cron (sk. backend tools/event_log_cleanup.py — ja vēl nav izveidots, izveido):

DELETE FROM event_log WHERE created_at < NOW() - INTERVAL '90 days';

Event schema

Whitelist (whitelist'ā server side)

event_name Kad Tipiski props
app_open Lietotne sākas startup_ms
app_background Lietotne fonā
screen_view Navigation uz jaunu ekrānu from_screen, dwell_ms_prev
ca_loaded CA veiksmīgi ielādēts features_count, area_ha_total, source: vmd|kml|package
ca_unloaded CA aizvērts dwell_ms
polygon_drawn Poligons saglabāts vertices_count, area_ha, source: tap|track
polygon_undone Lietotājs nospiest "Atcelt" pēc save
monitoring_added Pievienots Mani īpašumi
monitoring_removed Noņemts no Mani īpašumi
geofence_alert Robežas pārkāpums direction: out|in, distance_m
notification_received ntfy push topic, priority
feature_used Generic feature usage feature: kml_export|measurement|...
error Handled error error_type, hint (NEsūtīt error message text!)
settings_changed Settings toggle setting: keep_screen_on|..., value: true|false
theme_toggled Tēmas pārslēdzējs mode: dark|light|system
language_changed Valodas maiņa from, to

Constraints

  • _MAX_EVENTS_PER_BATCH = 100 events vienā POST
  • _MAX_PROPS_BYTES = 4096 (JSON serialized)
  • Rate limit: 60 batchi/min/device

Architecture

                     Mobile (CA Navigator)                          Server                          Grafana

┌────────────────────────┐                                                                        
│ Settings toggle        │   user opt-in                                                          
│ (default OFF)          │ ──────────────►  TelemetryService.setOptIn(true)                       
└────────────────────────┘                          │                                              
                                                    ▼                                              
                                          ┌─────────────────────┐                                  
                                          │ TelemetryService    │                                  
                                          │ - in-memory buffer  │                                  
                                          │ - flush 30s/50 evts │                                  
                                          │ - persist on offline│                                  
                                          └──────────┬──────────┘                                  
                                                     │ POST /api/event/batch                       
                                                     ▼                                              
                                                              ┌─────────────────────┐                              
                                                              │ vzd_local_service.py│                              
                                                              │  /api/event/batch   │                              
                                                              │  validate whitelist │                              
                                                              │  insert event_log   │                              
                                                              └──────────┬──────────┘                              
                                                                         │                                          
                                                                         ▼                                          
                                                                ┌─────────────┐                                    
                                                                │ event_log   │                                    
                                                                │ PostgreSQL  │                                    
                                                                │ retention   │                                    
                                                                │ 90d cron    │                                    
                                                                └──────┬──────┘                                    
                                                                       │ pg_database_size_bytes                    
                                                                       │ + custom queries                          
                                                                       ▼                                            
                                                                                          ┌──────────────────┐    
                                                                                          │ Grafana          │    
                                                                                          │ "Mobile Usage"   │    
                                                                                          │ dashboard        │    
                                                                                          └──────────────────┘    

Mobile API

TelemetryService.instance.track(eventName, {screen, props})

// Manuālais call no UI
TelemetryService.instance.track('feature_used', props: {'feature': 'kml_export'});

// Auto-track screen views — NavigatorObserver dara to bez paši UI koda
// MaterialApp.navigatorObservers: [_TelemetryNavigatorObserver()]

// Iespraust app_open
TelemetryService.instance.track('app_open', props: {'startup_ms': 1200});

Pārvaldība

// Opt-in
await TelemetryService.instance.setOptIn(true);

// Manuāls flush (pirms aizvēršanas)
await TelemetryService.instance.flush();

// GDPR — dzēst visu serverī
final ok = await TelemetryService.instance.deleteAllRemote();

Server API

POST /api/event/batch

Body:

{
  "device_token": "ca-nav-7f3a8b2c",
  "events": [
    {
      "event_name": "screen_view",
      "screen": "MapScreen",
      "props": {"from_screen": "InputScreen", "dwell_ms_prev": 4500},
      "app_version": "1.11.5+22",
      "app_build": "ca8f89a3",
      "platform": "android",
      "client_ts": "2026-05-07T10:15:30.123Z"
    }
  ]
}

Response (201):

{"accepted": 50, "rejected": 0}

DELETE /api/event/all?device_token=X (GDPR 17)

Response: {"deleted": 142} — kopējais events dzēsts.

Rate limit 3/h — pasargā pret abuse.


Grafana dashboard

Sk. server/observability/grafana/dashboards/klm-mobile-usage.json (provisioned, automātiski parādās folder "KLM").

Paneļi: 1. Daily Active Users (DAU)count(distinct device_token) WHERE created_at > now() - 24h 2. Top 10 ekrāni (24h) — pa ekrāna apmeklējumu skaitu 3. Top events (24h) — pa event_name skaitu 4. Drop-off funnel — InputScreen → CA loaded → MapScreen → polygon drawn 5. Errors per minute — by error_type 6. App version distribution — kuras versijas vēl produkcijā 7. Platform split — Android vs iOS vs unknown


Operational

Monitorings

/health row_counts un Prometheus klm_db_row_count{table="event_log"} rāda kopējo events skaitu.

Saprātīgs aug: - 50 lietotāji × 200 events/dienā = 10k events/diena - 90 dienu retention = ~900k events steady-state - ~50 MB disk space (JSONB props ~50 baitus average)

Disk space

Ja event_log audz strauji (>500 MB), pārbaudīt: - SELECT event_name, COUNT(*) FROM event_log GROUP BY 1 ORDER BY 2 DESC — kāds events spam - Iespējams: screen_view props per liels (drop_ms_prev liels JSON?) — samazināt

Cron retention

Pievienot crontab -l:

0 3 * * 3   docker exec klm-vzd-service psql $DATABASE_URL -c "DELETE FROM event_log WHERE created_at < NOW() - INTERVAL '90 days'" >> /var/log/klm-event-cleanup.log 2>&1 # klm-event-cleanup

(trešdienās 03:00, atstarpēts no LAD imports otrdienās).

Privacy review

Reizi 6 mēnešos: - Pārbaudīt _ALLOWED_EVENT_NAMES — vai nav jauni events ar PII risku - Pārbaudīt event log SQL kvēriju logus — nav device_token joining ar īsto user_subscription tabulu (citādi anonimitāte salauzta) - Atjaunot Privacy Policy, ja schema mainās