feat(ops): ECR-007 行为分析与 ECR-008 内容运营后台
落地埋点 ingest/数据看板、首页宫格 CMS 与测评上下架;含账号引导、问答流式与免责声明去重,以及 review P1 审计同事务修复。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
DROP INDEX IF EXISTS idx_growth_reports_latest_pair;
|
||||
DROP INDEX IF EXISTS idx_growth_reports_latest_solo;
|
||||
ALTER TABLE growth_reports DROP COLUMN IF EXISTS peer_profile_id;
|
||||
DROP INDEX IF EXISTS idx_user_sessions_token;
|
||||
DROP INDEX IF EXISTS idx_user_sessions_user_id;
|
||||
DROP TABLE IF EXISTS user_sessions;
|
||||
DROP INDEX IF EXISTS idx_users_phone_unique;
|
||||
ALTER TABLE users DROP COLUMN IF EXISTS nickname;
|
||||
ALTER TABLE users DROP COLUMN IF EXISTS password_hash;
|
||||
ALTER TABLE users DROP COLUMN IF EXISTS phone;
|
||||
@@ -0,0 +1,29 @@
|
||||
-- Account auth + report peer for birthday bootstrap bundles
|
||||
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS phone varchar(20) NULL;
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS password_hash text NULL;
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS nickname varchar(64) NULL;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_phone_unique
|
||||
ON users(phone) WHERE phone IS NOT NULL AND deleted_at IS NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_sessions (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id uuid NOT NULL REFERENCES users(id),
|
||||
token varchar(128) NOT NULL UNIQUE,
|
||||
expires_at timestamptz NOT NULL,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
revoked_at timestamptz NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_sessions_user_id ON user_sessions(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_sessions_token ON user_sessions(token) WHERE revoked_at IS NULL;
|
||||
|
||||
ALTER TABLE growth_reports ADD COLUMN IF NOT EXISTS peer_profile_id uuid NULL REFERENCES profiles(id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_growth_reports_latest_solo
|
||||
ON growth_reports(user_id, profile_id, type, created_at DESC)
|
||||
WHERE deleted_at IS NULL AND peer_profile_id IS NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_growth_reports_latest_pair
|
||||
ON growth_reports(user_id, profile_id, type, peer_profile_id, created_at DESC)
|
||||
WHERE deleted_at IS NULL AND peer_profile_id IS NOT NULL;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE users DROP COLUMN IF EXISTS ask_paid_quota_left;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Purchased ask quota packs (independent of membership deep-access)
|
||||
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS ask_paid_quota_left int NOT NULL DEFAULT 0;
|
||||
@@ -0,0 +1,2 @@
|
||||
DROP TABLE IF EXISTS analytics_events;
|
||||
DROP TABLE IF EXISTS analytics_sessions;
|
||||
@@ -0,0 +1,29 @@
|
||||
-- Ops-B analytics (ECR-007)
|
||||
|
||||
CREATE TABLE IF NOT EXISTS analytics_sessions (
|
||||
session_id varchar(64) PRIMARY KEY,
|
||||
device_key varchar(128) NOT NULL,
|
||||
user_id uuid NULL REFERENCES users(id),
|
||||
started_at timestamptz NOT NULL DEFAULT now(),
|
||||
ended_at timestamptz NULL,
|
||||
exit_page text NULL,
|
||||
duration_ms int NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_analytics_sessions_started ON analytics_sessions(started_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_analytics_sessions_user ON analytics_sessions(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_analytics_sessions_device ON analytics_sessions(device_key);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS analytics_events (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
session_id varchar(64) NOT NULL REFERENCES analytics_sessions(session_id),
|
||||
user_id uuid NULL REFERENCES users(id),
|
||||
name varchar(64) NOT NULL,
|
||||
page_path text NULL,
|
||||
props jsonb NOT NULL DEFAULT '{}',
|
||||
client_ts timestamptz NOT NULL,
|
||||
received_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_analytics_events_received ON analytics_events(received_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_analytics_events_name_day ON analytics_events(name, ((received_at AT TIME ZONE 'UTC')::date));
|
||||
CREATE INDEX IF NOT EXISTS idx_analytics_events_page ON analytics_events(page_path) WHERE page_path IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_analytics_events_session ON analytics_events(session_id);
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS home_tools;
|
||||
@@ -0,0 +1,29 @@
|
||||
-- Ops-C home tools CMS (ECR-008)
|
||||
|
||||
CREATE TABLE IF NOT EXISTS home_tools (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
row_index smallint NOT NULL CHECK (row_index IN (1, 2)),
|
||||
sort_order int NOT NULL DEFAULT 0,
|
||||
path text NOT NULL,
|
||||
icon varchar(32) NOT NULL,
|
||||
label varchar(32) NOT NULL,
|
||||
badge varchar(8) NULL,
|
||||
badge_tone varchar(8) NULL,
|
||||
enabled boolean NOT NULL DEFAULT true,
|
||||
updated_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_home_tools_row_sort ON home_tools(row_index, sort_order);
|
||||
|
||||
INSERT INTO home_tools (row_index, sort_order, path, icon, label, badge, badge_tone, enabled) VALUES
|
||||
(1, 1, '/scales/mbti-lite', 'mbti', '人格测试', NULL, NULL, true),
|
||||
(1, 2, '/star', 'star', '星座', NULL, NULL, true),
|
||||
(1, 3, '/portrait', 'portrait', '愈心解码', '热', 'hot', true),
|
||||
(1, 4, '/rhythm', 'rhythm', '身心节律', NULL, NULL, true),
|
||||
(1, 5, '/synastry', 'synastry', '合盘', '新', 'new', true),
|
||||
(1, 6, '/star', 'astro', '星象性格', NULL, NULL, true),
|
||||
(2, 1, '/companion', 'companion', '节气陪伴', NULL, NULL, true),
|
||||
(2, 2, '/ask', 'ask', 'AI问答', NULL, NULL, true),
|
||||
(2, 3, '/cards', 'cards', '意象卡片', NULL, NULL, true),
|
||||
(2, 4, '/reports', 'reports', '成长报告', '新', 'new', true),
|
||||
(2, 5, '/growth-plan', 'growth', '成长计划', NULL, NULL, true),
|
||||
(2, 6, '/relation', 'relation', '人格匹配', NULL, NULL, true);
|
||||
Reference in New Issue
Block a user