Files
john 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
Add TKMind platform extensions, H5/MindSpace stack, and deployment tooling.
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>
2026-06-14 21:30:20 +08:00

13 KiB
Raw Permalink Blame History

sidebar_position, title, sidebar_label, description
sidebar_position title sidebar_label description
3 数据模型 数据模型 Plaza 所有数据库表的完整字段定义、索引策略、约束规则和迁移说明

数据模型

总览

Plaza 新增 10 张业务表plaza_* 前缀 + ops_audit_log),复用现有 h5_usersh5_publish_records,不创建新的用户体系。

逻辑名与物理表映射(与 MindSpace 文档一致):

文档逻辑名 物理表
users h5_users
publications h5_publish_records

时间字段约定:Plaza 新表与现有 H5 库一致,使用 BIGINT 毫秒 UTCcreated_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_idcomment_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_countplaza_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.mjsmigrateSchema() 中做幂等 ALTER(与现有 MindSpace 迁移方式一致)。
  • 可选归档文件命名:ui/h5/migrations/V{n}__plaza_{description}.sql(仅作审计,执行入口仍是 initSchema)。
  • 新增字段必须有 DEFAULT 值,不允许直接在非空表上添加 NOT NULL 无默认值的列。
  • plaza_posts 的快照字段(user_slug 等)在写入后不自动同步更新,需要独立的后台对账任务。
  • 删除字段前先废弃读写代码,确认无流量后再执行 DDL。

不变量

  • 每个 publication_idplaza_posts 中最多出现一次(更新元数据走 PATCH,不换 publication)。
  • plaza_posts.status = hidden 必须在 h5_publish_records.status != 'online' 时下线联动触发(同一事务)。
  • comment_count 只统计 status = visible 的一级评论。
  • 所有计数字段不允许出现负数(应用层保证 DECR 前先检查当前值)。
  • plaza_follows 不允许 follower_id = followee_id