mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-23 06:40:53 -05:00
b0dde80ba9
Add a support modal with usage stats, tier and license links, share control, and offline-safe outbound CTAs. Surface support from the header, sidebar, user menu, dashboard card, and settings "Support & Community" section without hiding entry points when a supporter license is active. Introduce UsageStatsService and a persisted users.support_stats_reports_generated counter incremented on key report exports and custom report views. Add SupportPromptService for session-scoped soft toasts (after export, dashboard milestones, long session via POST /donate/request-soft-prompt). Wire consent-aware track_event names support.* and mirror funnel rows in DonationInteraction; fix has_recent_donation_click to treat link_clicked as a recent click. Document events and SUPPORT_* / migration notes in docs. Tests: tests/test_support_services.py for prompt and usage stats behavior.
55 lines
3.6 KiB
Markdown
55 lines
3.6 KiB
Markdown
# Telemetry Architecture
|
|
|
|
This document describes the privacy-aware, two-layer telemetry system: **base telemetry** (always-on, minimal) and **detailed analytics** (opt-in only).
|
|
|
|
## Overview
|
|
|
|
| Layer | When | Purpose | Events / Data |
|
|
|-------|------|---------|----------------|
|
|
| **Base telemetry** | Always (when OTLP sink is configured) | Install footprint, version/platform distribution, active installs | `base_telemetry.first_seen`, `base_telemetry.heartbeat` |
|
|
| **Detailed analytics** | Only when user opts in | Feature usage, funnels, errors, retention | All product events (e.g. `auth.login`, `timer.started`) |
|
|
|
|
- **Consent:** Stored in `installation.json` (`telemetry_enabled`) and synced to `settings.allow_analytics`. Source of truth: `installation_config.get_telemetry_preference()` / `is_telemetry_enabled()`.
|
|
- **Identifiers:** One **install_id** (random UUID in installation config) used for base telemetry and, when opt-in, sent with product events. Product events use internal `user_id` identity.
|
|
|
|
## Base Telemetry (Always-On)
|
|
|
|
- **Schema (no PII):** `install_id`, `app_version`, `platform`, `os_version`, `architecture`, `locale`, `timezone`, `first_seen_at`, `last_seen_at`, `heartbeat_at`, `release_channel`, `deployment_type`.
|
|
- **Events:** `base_telemetry.first_seen` (once per install), `base_telemetry.heartbeat` (e.g. daily via scheduler).
|
|
- **Sink:** Grafana Cloud OTLP with `identity = install_id`. No user-level linkage.
|
|
- **Trigger:** First-seen sent at app startup (idempotent). Heartbeat via scheduled task (e.g. 03:00 daily).
|
|
- **Retention:** Configure in Grafana backend (e.g. 12 months for base). No raw IP storage.
|
|
|
|
## Detailed Analytics (Opt-In Only)
|
|
|
|
- **Gated by:** `is_telemetry_enabled()` / `allow_analytics`. No product events sent without opt-in.
|
|
- **Events:** Existing names (e.g. `auth.login`, `timer.started`, `project.created`). Support funnel events use the `support.*` prefix (e.g. `support.modal_opened`); see [all_tracked_events.md](all_tracked_events.md). Optional prefix `analytics.*` in future.
|
|
- **Properties:** Include `install_id`, app_version, deployment, request context (path, browser, device) only when opted in.
|
|
- **Sink:** Grafana Cloud OTLP (`identity = user_id` for events).
|
|
- **Retention:** Per Grafana retention policy. Document in privacy policy.
|
|
|
|
## Consent Behavior
|
|
|
|
- **Opt-in:** Setup wizard or Admin → Settings (Privacy & Analytics) or Admin → Telemetry. Enabling triggers one opt-in install ping (`check_and_send_telemetry()`).
|
|
- **Opt-out:** Same toggles. Detailed analytics stop immediately; base telemetry continues (minimal footprint).
|
|
- **Data minimization:** Base layer is fixed schema. Detailed layer only when user agrees.
|
|
|
|
## Event Naming
|
|
|
|
- **Reserved:** `base_telemetry.*` for base layer. Do not use for product events.
|
|
- **Product events:** Keep current names (e.g. `timer.started`) or use `analytics.*`; all gated by opt-in.
|
|
|
|
## Implementation
|
|
|
|
- **Service:** `app/telemetry/service.py` — `send_base_first_seen()`, `send_base_heartbeat()`, `send_analytics_event()`, `is_detailed_analytics_enabled()`.
|
|
- **App entry points:** `app/__init__.py` — `track_event`, `track_page_view`, `identify_user` delegate to telemetry service (consent-aware).
|
|
- **Scheduler:** `app/utils/scheduled_tasks.py` — job `send_base_telemetry_heartbeat` (daily).
|
|
- **Startup:** In `create_app`, after scheduler start, call `send_base_first_seen()` once per install.
|
|
|
|
## Sink Configuration
|
|
|
|
- Base and detailed telemetry are emitted through the same OTLP sender in `app/telemetry/service.py`.
|
|
- Required configuration:
|
|
- `GRAFANA_OTLP_ENDPOINT`
|
|
- `GRAFANA_OTLP_TOKEN`
|