4e21ca937a
Deploy Documentation / deploy (push) Has been cancelled
Canary / Prepare Version (push) Has been cancelled
Canary / build-cli (push) Has been cancelled
Canary / Upload Install Script (push) Has been cancelled
Canary / bundle-desktop (push) Has been cancelled
Canary / bundle-desktop-intel (push) Has been cancelled
Canary / bundle-desktop-linux (push) Has been cancelled
Canary / bundle-desktop-windows (push) Has been cancelled
Canary / bundle-desktop-windows-cuda (push) Has been cancelled
Canary / Release (push) Has been cancelled
Unused Dependencies / machete (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / Check Rust Code Format (push) Has been cancelled
CI / Build and Test Rust Project (push) Has been cancelled
CI / Build Rust Project on Windows (push) Has been cancelled
CI / Check MSRV (push) Has been cancelled
CI / Lint Rust Code (push) Has been cancelled
CI / Check Generated Schemas are Up-to-Date (push) Has been cancelled
CI / Test and Lint Electron Desktop App (push) Has been cancelled
CI / H5 Plaza Tests and Build (push) Has been cancelled
Live Provider Tests / check-fork (push) Has been cancelled
Live Provider Tests / changes (push) Has been cancelled
Live Provider Tests / Build Binary (push) Has been cancelled
Live Provider Tests / Smoke Tests (push) Has been cancelled
Live Provider Tests / Smoke Tests (Code Execution) (push) Has been cancelled
Live Provider Tests / Compaction Tests (push) Has been cancelled
Live Provider Tests / goose server HTTP integration tests (push) Has been cancelled
Publish Ask AI Bot Docker Image / docker (push) Has been cancelled
Publish Docker Image / docker (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Fork goose with custom MCP widgets, platform extensions (aider, git, web, search), MindSpace H5 backend/frontend, Plaza/Ops UIs, and deploy scripts for tkmind.cn. Co-authored-by: Cursor <cursoragent@cursor.com>
13 KiB
13 KiB
sidebar_position, title, sidebar_label, description
| sidebar_position | title | sidebar_label | description |
|---|---|---|---|
| 3 | 数据模型 | 数据模型 | Plaza 所有数据库表的完整字段定义、索引策略、约束规则和迁移说明 |
数据模型
总览
Plaza 新增 10 张业务表(plaza_* 前缀 + ops_audit_log),复用现有 h5_users 和 h5_publish_records,不创建新的用户体系。
逻辑名与物理表映射(与 MindSpace 文档一致):
| 文档逻辑名 | 物理表 |
|---|---|
| users | h5_users |
| publications | h5_publish_records |
时间字段约定:Plaza 新表与现有 H5 库一致,使用 BIGINT 毫秒 UTC(created_at / updated_at / published_at 等),不使用 DATETIME。
h5_users (现有)
│
├──< plaza_posts 广场帖子(每条对应一个已发布的 publication)
│ │
│ ├──< plaza_reactions 点赞 / 收藏 / 分享
│ ├──< plaza_comments 评论(支持二级回复)
│ └──< plaza_comment_reactions 评论点赞
│
└──< plaza_follows 关注关系(创作者 ↔ 粉丝)
plaza_categories 广场分类(独立配置表)
└──< plaza_posts
plaza_algorithm_config 热度公式权重(键值表)
plaza_reports 用户举报
plaza_featured 精选位配置
ops_audit_log 运营操作审计(追加-only)
plaza_posts(广场帖子)
CREATE TABLE plaza_posts (
id CHAR(36) NOT NULL,
publication_id CHAR(36) NOT NULL, -- → h5_publish_records.id
user_id CHAR(36) NOT NULL, -- → h5_users.id
-- 快照字段(冗余,避免跨表 JOIN)
title VARCHAR(200) NOT NULL,
summary VARCHAR(500) NOT NULL DEFAULT '',
cover_url VARCHAR(500) NOT NULL DEFAULT '',
user_slug VARCHAR(100) NOT NULL, -- 快照,发帖时写入
user_display_name VARCHAR(100) NOT NULL,
user_avatar_url VARCHAR(500) NOT NULL DEFAULT '',
-- 分类和标签
category_id CHAR(36) NOT NULL, -- → plaza_categories.id
tags JSON NOT NULL DEFAULT (JSON_ARRAY()), -- 最多 5 个
-- 状态
status ENUM(
'pending_review', -- 待审核(默认)
'published', -- 审核通过,公开展示
'hidden', -- 被运营隐藏或 publication 下线
'rejected' -- 审核拒绝
) NOT NULL DEFAULT 'pending_review',
-- 互动计数(热计数用 Redis,定时同步到这里)
view_count INT UNSIGNED NOT NULL DEFAULT 0,
like_count INT UNSIGNED NOT NULL DEFAULT 0,
collect_count INT UNSIGNED NOT NULL DEFAULT 0,
comment_count INT UNSIGNED NOT NULL DEFAULT 0,
share_count INT UNSIGNED NOT NULL DEFAULT 0,
-- 热度
hot_score DOUBLE NOT NULL DEFAULT 0,
hot_updated_at BIGINT NULL,
-- 设置
allow_comment TINYINT(1) NOT NULL DEFAULT 1,
-- 时间(毫秒 UTC)
published_at BIGINT NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY uq_publication (publication_id), -- 每个 publication 只能发一次
KEY idx_user_status (user_id, status),
KEY idx_category_hot (category_id, status, hot_score DESC),
KEY idx_published_at (published_at DESC),
KEY idx_status_hot (status, hot_score DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
字段说明:
publication_id唯一约束:同一个发布记录只能出现在广场一次,防止重复发布。- 快照字段(
user_slug等)在发帖时写入,此后不随用户改名而变。如果用户改名,需要额外的更新任务,但不影响已有帖子的显示。 status = hidden覆盖两种场景:运营主动隐藏、publication 被原作者下线。hot_score由后台定时任务计算写入,不在每次请求时实时计算。
plaza_reactions(点赞 / 收藏 / 分享)
CREATE TABLE plaza_reactions (
id CHAR(36) NOT NULL,
post_id CHAR(36) NOT NULL, -- → plaza_posts.id
user_id CHAR(36) NOT NULL, -- → h5_users.id
type ENUM(
'like',
'collect',
'share'
) NOT NULL,
created_at BIGINT NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY uq_user_post_type (post_id, user_id, type), -- 同一用户同一帖子同类型只能有一条
KEY idx_post_type (post_id, type),
KEY idx_user_type (user_id, type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
触发器逻辑(应用层实现,不用数据库触发器):
- 插入 reaction → Redis INCR
plaza:post:{id}:like_count - 删除 reaction(取消点赞)→ Redis DECR
- 定时任务每 5 分钟将 Redis 计数同步到
plaza_posts对应字段
plaza_comments(评论)
CREATE TABLE plaza_comments (
id CHAR(36) NOT NULL,
post_id CHAR(36) NOT NULL, -- → plaza_posts.id
user_id CHAR(36) NOT NULL, -- → h5_users.id
parent_id CHAR(36) NULL, -- 二级回复时指向父评论,NULL 表示一级评论
-- 内容
content VARCHAR(500) NOT NULL,
-- 状态
status ENUM(
'visible',
'deleted', -- 用户自己删除(内容替换为空,记录保留)
'flagged', -- 被举报,等待审核
'hidden' -- 运营隐藏
) NOT NULL DEFAULT 'visible',
-- 计数
like_count INT UNSIGNED NOT NULL DEFAULT 0,
reply_count INT UNSIGNED NOT NULL DEFAULT 0, -- 仅一级评论有效
-- 删除人标记
deleted_by ENUM('user', 'ops') NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
PRIMARY KEY (id),
KEY idx_post_visible (post_id, status, created_at DESC),
KEY idx_parent (parent_id),
KEY idx_user (user_id, created_at DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
规则:
- 只支持两级:一级评论(
parent_id IS NULL)和二级回复(parent_id指向一级)。 - 二级回复不再允许继续嵌套,前端也不展示更深的层级。
- 删除评论时不物理删除,将
content设为空字符串,status设为deleted,保留reply_count用于展示"该评论已删除,有 N 条回复"。 post_id的comment_count只计算status = visible的一级评论数量。
plaza_follows(关注关系)
CREATE TABLE plaza_follows (
follower_id CHAR(36) NOT NULL, -- 关注者 → h5_users.id
followee_id CHAR(36) NOT NULL, -- 被关注者 → h5_users.id
created_at BIGINT NOT NULL,
PRIMARY KEY (follower_id, followee_id),
KEY idx_followee (followee_id, created_at DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
说明:
- 不允许自己关注自己(应用层校验:
follower_id != followee_id)。 h5_users表新增冗余计数字段plaza_following_count和plaza_follower_count,关注/取关时事务内更新。- 取关是物理删除行。
plaza_categories(广场分类)
CREATE TABLE plaza_categories (
id CHAR(36) NOT NULL,
name VARCHAR(50) NOT NULL,
slug VARCHAR(50) NOT NULL, -- URL 友好,如 work-report
icon VARCHAR(10) NOT NULL DEFAULT '', -- emoji 或图标代码
description VARCHAR(200) NOT NULL DEFAULT '',
sort_order INT NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at BIGINT NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY uq_slug (slug),
KEY idx_sort (is_active, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
初始分类数据:
| name | slug | icon | sort_order |
|---|---|---|---|
| 职场报告 | work-report | 📊 | 1 |
| 学习笔记 | study-notes | 📚 | 2 |
| 创意作品 | creative | 🎨 | 3 |
| 门店展示 | business | 🏪 | 4 |
| 旅行攻略 | travel | ✈️ | 5 |
| 数据分析 | data-analysis | 📈 | 6 |
| 生活记录 | lifestyle | 🌿 | 7 |
| 其他 | other | 💡 | 99 |
plaza_comment_reactions(评论点赞)
CREATE TABLE plaza_comment_reactions (
id CHAR(36) NOT NULL,
comment_id CHAR(36) NOT NULL, -- → plaza_comments.id
user_id CHAR(36) NOT NULL, -- → h5_users.id
created_at BIGINT NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY uq_user_comment (comment_id, user_id),
KEY idx_comment (comment_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
- 点赞/取消点赞时同步更新
plaza_comments.like_count(事务内,不走 Redis)。 - 不提供独立 Redis 键;评论点赞量低于帖子级互动,直接写 MySQL 即可。
plaza_algorithm_config(热度权重)
见 05-feed-algorithm 中的建表 SQL。Sprint 3 引入。
plaza_reports(举报)
见 06-ops-platform 中的建表 SQL。Sprint 5 引入。
plaza_featured(精选位)
见 06-ops-platform 中的建表 SQL。Sprint 5 引入。
ops_audit_log(运营审计)
见 06-ops-platform 中的建表 SQL。Sprint 5 引入。
h5_users / h5_publish_records 扩展字段
在现有表上通过 db.mjs 增量迁移添加:
ALTER TABLE h5_users
ADD COLUMN plaza_post_count INT UNSIGNED NOT NULL DEFAULT 0,
ADD COLUMN plaza_follower_count INT UNSIGNED NOT NULL DEFAULT 0,
ADD COLUMN plaza_following_count INT UNSIGNED NOT NULL DEFAULT 0,
ADD COLUMN plaza_verified TINYINT(1) NOT NULL DEFAULT 0,
ADD COLUMN plaza_post_banned TINYINT(1) NOT NULL DEFAULT 0,
ADD COLUMN plaza_comment_banned TINYINT(1) NOT NULL DEFAULT 0,
ADD COLUMN ops_role ENUM('none','reviewer','editor','ops_admin') NOT NULL DEFAULT 'none';
ALTER TABLE h5_publish_records
ADD COLUMN plaza_view_count BIGINT NOT NULL DEFAULT 0,
ADD COLUMN plaza_like_count BIGINT NOT NULL DEFAULT 0;
total_likes(用户主页 API):不单独落库,查询时 SUM(plaza_posts.like_count) WHERE user_id = ? AND status = 'published',或维护 h5_users.plaza_total_likes 冗余字段(Sprint 2 可选优化)。
Redis 数据结构
# 实时计数(定时同步到 MySQL)
plaza:post:{post_id}:view_count STRING INCR
plaza:post:{post_id}:like_count STRING INCR/DECR
# Feed 缓存(TTL 5 分钟)
plaza:feed:hot:{category_id}:page:{n} STRING JSON 数组,热门帖子 ID 列表
plaza:feed:new:{category_id}:page:{n} STRING JSON 数组,最新帖子 ID 列表
# 用户行为缓存(判断当前用户是否已点赞)
plaza:user:{user_id}:liked SET post_id 集合,TTL 30 分钟
索引策略
| 查询场景 | 使用索引 |
|---|---|
| 广场首页热门 feed | idx_status_hot (status, hot_score DESC) |
| 分类热门 feed | idx_category_hot (category_id, status, hot_score DESC) |
| 用户主页帖子列表 | idx_user_status (user_id, status) |
| 最新帖子列表 | idx_published_at (published_at DESC) |
| 帖子评论列表 | idx_post_visible (post_id, status, created_at DESC) |
| 用户关注列表 | idx_followee (followee_id, created_at DESC) |
迁移规范
- 每次 schema 变更:更新
ui/h5/schema.sql,并在db.mjs的migrateSchema()中做幂等ALTER(与现有 MindSpace 迁移方式一致)。 - 可选归档文件命名:
ui/h5/migrations/V{n}__plaza_{description}.sql(仅作审计,执行入口仍是initSchema)。 - 新增字段必须有 DEFAULT 值,不允许直接在非空表上添加 NOT NULL 无默认值的列。
plaza_posts的快照字段(user_slug等)在写入后不自动同步更新,需要独立的后台对账任务。- 删除字段前先废弃读写代码,确认无流量后再执行 DDL。
不变量
- 每个
publication_id在plaza_posts中最多出现一次(更新元数据走PATCH,不换 publication)。 plaza_posts.status = hidden必须在h5_publish_records.status != 'online'时下线联动触发(同一事务)。comment_count只统计status = visible的一级评论。- 所有计数字段不允许出现负数(应用层保证 DECR 前先检查当前值)。
plaza_follows不允许follower_id = followee_id。