mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-19 04:40:32 -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.
3.6 KiB
3.6 KiB
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 tosettings.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_ididentity.
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 thesupport.*prefix (e.g.support.modal_opened); see all_tracked_events.md. Optional prefixanalytics.*in future. - Properties: Include
install_id, app_version, deployment, request context (path, browser, device) only when opted in. - Sink: Grafana Cloud OTLP (
identity = user_idfor 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 useanalytics.*; 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_userdelegate to telemetry service (consent-aware). - Scheduler:
app/utils/scheduled_tasks.py— jobsend_base_telemetry_heartbeat(daily). - Startup: In
create_app, after scheduler start, callsend_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_ENDPOINTGRAFANA_OTLP_TOKEN