Add privacy-safe product analytics
Establish an idempotent analytics pipeline and internal decision dashboard while keeping event metadata allowlisted and account deletion enforceable.
This commit is contained in:
+258
-1
@@ -73,6 +73,33 @@ paths:
|
||||
responses:
|
||||
"204": { description: Session revoked }
|
||||
default: { $ref: "#/components/responses/Error" }
|
||||
/v1/analytics/events:
|
||||
post:
|
||||
security:
|
||||
- {}
|
||||
- bearerAuth: []
|
||||
summary: Idempotently accept privacy-minimized product events
|
||||
description: |
|
||||
Accepts pre-login or authenticated client events. The random
|
||||
installation UUID is stored only as a digest. When a valid bearer
|
||||
session is supplied, the installation is linked to the account and is
|
||||
deleted with that account. Audio, user text, prompts, transcripts,
|
||||
model output, credentials and arbitrary properties are never accepted.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/ProductAnalyticsBatchRequest" }
|
||||
responses:
|
||||
"200":
|
||||
description: Atomic batch acceptance and replay counts
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/ProductAnalyticsBatchResponse" }
|
||||
"400": { $ref: "#/components/responses/Error" }
|
||||
"409": { $ref: "#/components/responses/Error" }
|
||||
"422": { $ref: "#/components/responses/Error" }
|
||||
default: { $ref: "#/components/responses/Error" }
|
||||
/v1/account:
|
||||
get:
|
||||
summary: Return the account profile
|
||||
@@ -571,6 +598,22 @@ paths:
|
||||
schema: { $ref: "#/components/schemas/AdminReferralOverview" }
|
||||
"400": { description: Range is invalid }
|
||||
"401": { description: Session is invalid }
|
||||
/v1/admin/analytics:
|
||||
get:
|
||||
security:
|
||||
- adminMtls: []
|
||||
adminSession: []
|
||||
summary: Return product growth, retention, usage and monetization analytics
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AdminRange"
|
||||
responses:
|
||||
"200":
|
||||
description: Privacy-minimized product analytics aggregates
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/AdminProductAnalytics" }
|
||||
"400": { description: Range is invalid }
|
||||
"401": { description: Session is invalid }
|
||||
/v1/admin/users:
|
||||
get:
|
||||
security:
|
||||
@@ -904,6 +947,69 @@ components:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/GatewayError" }
|
||||
schemas:
|
||||
ProductAnalyticsEvent:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [clientEventId, eventType, occurredAt, surface]
|
||||
properties:
|
||||
clientEventId: { type: string, format: uuid }
|
||||
eventType:
|
||||
type: string
|
||||
enum:
|
||||
- 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
|
||||
occurredAt: { type: string, format: date-time }
|
||||
surface: { type: string, enum: [APP, KEYBOARD, INVITE_WEB] }
|
||||
acquisitionChannel:
|
||||
type: string
|
||||
enum: [APP_STORE_ORGANIC, REFERRAL, SOCIAL_CONTENT, UNKNOWN]
|
||||
feature:
|
||||
type: string
|
||||
enum: [TRANSCRIPTION, POLISH, AI_ASSISTANT, AGENT, HOTWORD, OTHER]
|
||||
executionMode: { type: string, enum: [MANAGED, LOCAL, BYOK] }
|
||||
failureCategory:
|
||||
type: string
|
||||
enum: [NETWORK, PROVIDER, TIMEOUT, CANCELLED, INSUFFICIENT_CREDITS, VALIDATION, UNKNOWN]
|
||||
durationBucket:
|
||||
type: string
|
||||
enum: [LT_1S, S1_TO_3, S3_TO_10, S10_TO_30, GTE_30S]
|
||||
appVersion:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 32
|
||||
pattern: "^[A-Za-z0-9._+-]+$"
|
||||
osVersion:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 32
|
||||
pattern: "^[A-Za-z0-9._+-]+$"
|
||||
ProductAnalyticsBatchRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [installationId, events]
|
||||
properties:
|
||||
installationId: { type: string, format: uuid }
|
||||
events:
|
||||
type: array
|
||||
minItems: 1
|
||||
maxItems: 50
|
||||
items: { $ref: "#/components/schemas/ProductAnalyticsEvent" }
|
||||
ProductAnalyticsBatchResponse:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [accepted, replayed]
|
||||
properties:
|
||||
accepted: { type: integer, minimum: 0, maximum: 50 }
|
||||
replayed: { type: integer, minimum: 0, maximum: 50 }
|
||||
AdminSessionState:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -978,7 +1084,7 @@ components:
|
||||
properties:
|
||||
label:
|
||||
type: string
|
||||
enum: [邀请码创建, 成功绑定, 有效使用并奖励, 待资格确认, 不符合奖励条件]
|
||||
enum: [邀请码创建, 成功绑定, 有效使用并奖励]
|
||||
count: { type: integer, format: int64, minimum: 0 }
|
||||
AdminReferralRank:
|
||||
type: object
|
||||
@@ -1002,6 +1108,157 @@ components:
|
||||
ranking:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/AdminReferralRank" }
|
||||
AdminAnalyticsRate:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [numerator, denominator]
|
||||
properties:
|
||||
numerator: { type: integer, format: int64, minimum: 0 }
|
||||
denominator: { type: integer, format: int64, minimum: 0 }
|
||||
percent: { type: ["number", "null"], minimum: 0, maximum: 100 }
|
||||
AdminAnalyticsFunnelStep:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [label, count]
|
||||
properties:
|
||||
label: { type: string, maxLength: 64 }
|
||||
count: { type: integer, format: int64, minimum: 0 }
|
||||
AdminAnalyticsChannel:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [channel, installations, activated, activationRate]
|
||||
properties:
|
||||
channel:
|
||||
type: string
|
||||
enum: [APP_STORE_ORGANIC, REFERRAL, SOCIAL_CONTENT, UNKNOWN]
|
||||
installations: { type: integer, format: int64, minimum: 0 }
|
||||
activated: { type: integer, format: int64, minimum: 0 }
|
||||
activationRate: { $ref: "#/components/schemas/AdminAnalyticsRate" }
|
||||
AdminAnalyticsCohort:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [cohortDate, size]
|
||||
properties:
|
||||
cohortDate: { type: string, format: date }
|
||||
size: { type: integer, format: int64, minimum: 0 }
|
||||
d1:
|
||||
anyOf:
|
||||
- { $ref: "#/components/schemas/AdminAnalyticsRate" }
|
||||
- { type: "null" }
|
||||
d7:
|
||||
anyOf:
|
||||
- { $ref: "#/components/schemas/AdminAnalyticsRate" }
|
||||
- { type: "null" }
|
||||
d30:
|
||||
anyOf:
|
||||
- { $ref: "#/components/schemas/AdminAnalyticsRate" }
|
||||
- { type: "null" }
|
||||
AdminAnalyticsFeatureUsage:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [feature, executionMode, users, successes]
|
||||
properties:
|
||||
feature:
|
||||
type: string
|
||||
enum: [TRANSCRIPTION, POLISH, AI_ASSISTANT, AGENT, HOTWORD, OTHER]
|
||||
executionMode: { type: string, enum: [MANAGED, LOCAL, BYOK] }
|
||||
users: { type: integer, format: int64, minimum: 0 }
|
||||
successes: { type: integer, format: int64, minimum: 0 }
|
||||
AdminProductAnalytics:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- period
|
||||
- northStar
|
||||
- growth
|
||||
- activity
|
||||
- consumption
|
||||
- monetization
|
||||
- growthFunnel
|
||||
- retention
|
||||
- aiFeatures
|
||||
- referralFunnel
|
||||
- guardrails
|
||||
properties:
|
||||
period:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [from, until]
|
||||
properties:
|
||||
from: { type: string, format: date-time }
|
||||
until: { type: string, format: date-time }
|
||||
northStar:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [weeklyAiActiveUsers, previousWeeklyAiActiveUsers]
|
||||
properties:
|
||||
weeklyAiActiveUsers: { type: integer, format: int64, minimum: 0 }
|
||||
previousWeeklyAiActiveUsers: { type: integer, format: int64, minimum: 0 }
|
||||
weekOverWeekPercent: { type: ["number", "null"] }
|
||||
growth:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [newInstallations, newAccounts, activation24h, channels]
|
||||
properties:
|
||||
newInstallations: { type: integer, format: int64, minimum: 0 }
|
||||
newAccounts: { type: integer, format: int64, minimum: 0 }
|
||||
activation24h: { $ref: "#/components/schemas/AdminAnalyticsRate" }
|
||||
medianTimeToValueMinutes: { type: ["number", "null"], minimum: 0 }
|
||||
channels:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/AdminAnalyticsChannel" }
|
||||
activity:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [dau, wau, mau, successfulAiRequests]
|
||||
properties:
|
||||
dau: { type: integer, format: int64, minimum: 0 }
|
||||
wau: { type: integer, format: int64, minimum: 0 }
|
||||
mau: { type: integer, format: int64, minimum: 0 }
|
||||
stickinessPercent: { type: ["number", "null"], minimum: 0, maximum: 100 }
|
||||
successfulAiRequests: { type: integer, format: int64, minimum: 0 }
|
||||
successfulRequestsPerActiveUser: { type: ["number", "null"], minimum: 0 }
|
||||
consumption:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [totalCredits]
|
||||
properties:
|
||||
totalCredits: { type: integer, format: int64, minimum: 0 }
|
||||
averageDailyCreditsPerActiveUser: { type: ["number", "null"], minimum: 0 }
|
||||
medianUserDailyCredits: { type: ["number", "null"], minimum: 0 }
|
||||
averageCreditsPerManagedRequest: { type: ["number", "null"], minimum: 0 }
|
||||
monetization:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
[payingUsers, purchases, creditsPurchased, conversion7d, conversion30d, repeatPurchaseRate]
|
||||
properties:
|
||||
payingUsers: { type: integer, format: int64, minimum: 0 }
|
||||
purchases: { type: integer, format: int64, minimum: 0 }
|
||||
creditsPurchased: { type: integer, format: int64, minimum: 0 }
|
||||
conversion7d: { $ref: "#/components/schemas/AdminAnalyticsRate" }
|
||||
conversion30d: { $ref: "#/components/schemas/AdminAnalyticsRate" }
|
||||
repeatPurchaseRate: { $ref: "#/components/schemas/AdminAnalyticsRate" }
|
||||
growthFunnel:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/AdminAnalyticsFunnelStep" }
|
||||
retention:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/AdminAnalyticsCohort" }
|
||||
aiFeatures:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/AdminAnalyticsFeatureUsage" }
|
||||
referralFunnel:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/AdminAnalyticsFunnelStep" }
|
||||
guardrails:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [clientAiSuccessRate, managedSuccessRate, creditBlockedUsers]
|
||||
properties:
|
||||
clientAiSuccessRate: { $ref: "#/components/schemas/AdminAnalyticsRate" }
|
||||
managedSuccessRate: { $ref: "#/components/schemas/AdminAnalyticsRate" }
|
||||
creditBlockedUsers: { type: integer, format: int64, minimum: 0 }
|
||||
AdminUserSummary:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
Reference in New Issue
Block a user