Add privacy-safe product analytics
CI / verify (push) Has been cancelled
CI / publish (push) Has been cancelled

Establish an idempotent analytics pipeline and internal decision dashboard while keeping event metadata allowlisted and account deletion enforceable.
This commit is contained in:
Rocky
2026-08-20 15:20:01 +08:00
parent 231c5040a5
commit 4b465e0e5e
38 changed files with 4275 additions and 80 deletions
@@ -0,0 +1,103 @@
CREATE TABLE product_analytics_installations (
installation_hash CHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
account_id VARCHAR(36) CHARACTER SET ascii COLLATE ascii_bin NULL,
created_at DATETIME(6) NOT NULL,
updated_at DATETIME(6) NOT NULL,
PRIMARY KEY (installation_hash),
INDEX ix_product_analytics_installations_account (account_id),
CONSTRAINT fk_product_analytics_installations_account
FOREIGN KEY (account_id) REFERENCES accounts (id) ON DELETE CASCADE
) ENGINE = InnoDB;
CREATE TABLE product_analytics_events (
installation_hash CHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
client_event_id CHAR(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
event_name VARCHAR(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
occurred_at DATETIME(6) NOT NULL,
surface VARCHAR(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
acquisition_channel VARCHAR(32) CHARACTER SET ascii COLLATE ascii_bin NULL,
feature VARCHAR(32) CHARACTER SET ascii COLLATE ascii_bin NULL,
execution_mode VARCHAR(16) CHARACTER SET ascii COLLATE ascii_bin NULL,
failure_category VARCHAR(32) CHARACTER SET ascii COLLATE ascii_bin NULL,
duration_bucket VARCHAR(16) CHARACTER SET ascii COLLATE ascii_bin NULL,
app_version VARCHAR(32) CHARACTER SET ascii COLLATE ascii_bin NULL,
os_version VARCHAR(32) CHARACTER SET ascii COLLATE ascii_bin NULL,
payload_hash CHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
received_at DATETIME(6) NOT NULL,
PRIMARY KEY (installation_hash, client_event_id),
INDEX ix_product_analytics_events_type_occurred (event_name, occurred_at),
INDEX ix_product_analytics_events_occurred (occurred_at),
CONSTRAINT fk_product_analytics_events_installation
FOREIGN KEY (installation_hash)
REFERENCES product_analytics_installations (installation_hash)
ON DELETE CASCADE,
CONSTRAINT chk_product_analytics_events_type CHECK (
event_name IN (
'FIRST_OPEN',
'SESSION_STARTED',
'KEYBOARD_ACTIVATED',
'AI_FEATURE_STARTED',
'AI_FEATURE_SUCCEEDED',
'AI_FEATURE_FAILED',
'PURCHASE_VIEWED',
'PURCHASE_STARTED',
'PURCHASE_CANCELLED',
'REFERRAL_SHARED',
'INVITE_OPENED'
)
),
CONSTRAINT chk_product_analytics_events_surface CHECK (
surface IN ('APP', 'KEYBOARD', 'INVITE_WEB')
),
CONSTRAINT chk_product_analytics_events_acquisition CHECK (
acquisition_channel IS NULL
OR acquisition_channel IN (
'APP_STORE_ORGANIC',
'REFERRAL',
'SOCIAL_CONTENT',
'UNKNOWN'
)
),
CONSTRAINT chk_product_analytics_events_feature CHECK (
feature IS NULL
OR feature IN (
'TRANSCRIPTION',
'POLISH',
'AI_ASSISTANT',
'AGENT',
'HOTWORD',
'OTHER'
)
),
CONSTRAINT chk_product_analytics_events_execution CHECK (
execution_mode IS NULL OR execution_mode IN ('MANAGED', 'LOCAL', 'BYOK')
),
CONSTRAINT chk_product_analytics_events_failure CHECK (
failure_category IS NULL
OR failure_category IN (
'NETWORK',
'PROVIDER',
'TIMEOUT',
'CANCELLED',
'INSUFFICIENT_CREDITS',
'VALIDATION',
'UNKNOWN'
)
),
CONSTRAINT chk_product_analytics_events_duration CHECK (
duration_bucket IS NULL
OR duration_bucket IN ('LT_1S', 'S1_TO_3', 'S3_TO_10', 'S10_TO_30', 'GTE_30S')
)
) ENGINE = InnoDB;
-- First-party invitation page views are counted without cookies, IP addresses,
-- user agents, installation IDs, or referral codes.
CREATE TABLE product_analytics_daily_counters (
counter_date DATE NOT NULL,
counter_name VARCHAR(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
counter_value BIGINT UNSIGNED NOT NULL DEFAULT 0,
updated_at DATETIME(6) NOT NULL,
PRIMARY KEY (counter_date, counter_name),
CONSTRAINT chk_product_analytics_daily_counter_name
CHECK (counter_name IN ('INVITE_PAGE_OPENED'))
) ENGINE = InnoDB;