feat(analytics): opt-in usage analytics with server ingest and settings toggle
Build and Deploy / build-and-push (push) Successful in 4m17s
Build and Deploy / build-and-push (push) Successful in 4m17s
- Server: POST /api/analytics endpoint with per-IP rate limit (5/min), batch validation (≤50 events, event_type regex, UUID dedup, clock check), INSERT OR IGNORE for idempotency, and migration 004_analytics.sql - Client (solitaire_data): AnalyticsClient with in-memory Mutex buffer, UUID session_id per launch, async flush via background task - Engine: AnalyticsPlugin records game_won, game_forfeit, game_start, achievement_unlocked; flushes immediately on game-end, every 60 s otherwise - Settings UI: Privacy section with ON/OFF toggle, hidden in local-only mode - Default: analytics_enabled = false (explicit opt-in required) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
-- Analytics event store.
|
||||
-- Events are write-only; the server never modifies rows after insert.
|
||||
-- `INSERT OR IGNORE` on `id` makes submissions idempotent.
|
||||
CREATE TABLE IF NOT EXISTS analytics_events (
|
||||
id TEXT PRIMARY KEY NOT NULL, -- UUID v4 minted by the client
|
||||
user_id TEXT, -- optional username; NULL = anonymous
|
||||
session_id TEXT NOT NULL, -- UUID v4, one per app launch
|
||||
event_type TEXT NOT NULL, -- e.g. "game_won", "game_start"
|
||||
payload TEXT NOT NULL DEFAULT '{}', -- JSON blob, event-specific fields
|
||||
client_time TEXT NOT NULL, -- ISO-8601, from the client clock
|
||||
received_at TEXT NOT NULL -- ISO-8601, server clock at ingest
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_analytics_event_type ON analytics_events(event_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_analytics_received_at ON analytics_events(received_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_analytics_user_id ON analytics_events(user_id);
|
||||
Reference in New Issue
Block a user