feat(ops): ECR-007 行为分析与 ECR-008 内容运营后台
ci / h5 (push) Canceled after 0s
ci / api (push) Canceled after 0s
ci / ess-docs (push) Canceled after 0s

落地埋点 ingest/数据看板、首页宫格 CMS 与测评上下架;含账号引导、问答流式与免责声明去重,以及 review P1 审计同事务修复。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-07 02:26:16 +08:00
co-authored by Cursor
parent 7e9023f0a8
commit 7ab9add5dd
132 changed files with 8276 additions and 491 deletions
@@ -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);