games-development-ai/contracts/db-schemas/V23.0.0__create_game_community_social.sql
lili 3f35acb4d3 feat(community): U3 R-SOC 评论/关注/排行ZSET/弹幕WS
社区社交后端四子能力(game-module-community),克隆通知底座/feed互动幂等范式:

- 评论 Comments:CRUD + 举报转 compliance。删除按 userId 归属强校验(防越权删他人评论),
  举报落本端举报态幂等 + 事务提交后 afterCommit 接缝(compliance 无受理 -api,留桩 OPEN ITEM)。
- 关注 Follow:active 软开关幂等切换(不删行,范本=feed FeedInteractLog),不能关注自己,
  并发双插由 DB 唯一键 DuplicateKeyException CAS 收敛;粉丝数/关注数 countActive。
- 排行 Ranking:Redis ZSET + ZSET↔DB 一致性窗口。DB=真相、ZSET=缓存索引:
  写穿透双写(DB 原子累加 + ZSET incrementScore)、ZSET 缺失/启动从 DB 回填重建、最终一致;
  维度白名单 RankDimensionEnum(game_hot/creator_hot)。
- 弹幕 Danmaku:WebSocket 单机最小实(LocalWebSocketMessageSender),自维护房间 gameId→sessionId
  注册表做房间维度广播(框架仅按用户维度推送),断连懒清理;多实例需切 sender-type=redis(MQ future-state 未部署)。

契约/库表:
- Flyway V23.0.0(U3 独占 V23.x):game_community_comment/follow/rank/danmaku 四表 +
  幂等唯一键(follow uk(user_id,target_user_id,deleted,tenant_id)、rank uk(dimension,target_id,...)),
  同步 huijing-server/db/migration + contracts/db-schemas。
- community.yaml additive 加 8 个 app 端点 + 5 个 schema(既有冻结)。
- 错误码段 1-107-004 评论 / 005 关注 / 006 排行 / 007 弹幕。

验证:mvn -pl game-module-community/game-module-community-server -am test -o 全绿
(57 tests:新增 U3 35 + 既有 22;CommentService 9 / FollowService 8 / RankService 8 / Danmaku 10)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 11:01:24 -07:00

108 lines
10 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =============================================================================
-- 契约 #2 DB 迁移 | 主题:community 社区社交(评论 + 关注 + 排行 + 弹幕)(U3 R-SOC,plan002)| owner:U3
-- 文件:V23.0.0__create_game_community_social.sql(Flyway,只新增;已合入禁止修改,回滚写新补偿迁移 V23.0.1)
-- 版本号:U3 独占 V23.x(全局当前最大 V22;切勿与他人版本冲突)。
-- 内容:community 四张社交新表:
-- 1. game_community_comment —— 评论(CRUD + 举报转 compliance);
-- 2. game_community_follow —— 关注(active 软开关幂等切换,不删行);
-- 3. game_community_rank —— 排行权威源(Redis ZSET 的回填源 / 一致性兜底,DB=真相、ZSET=缓存索引);
-- 4. game_community_danmaku —— 弹幕(WebSocket 广播 + 落库可回放)。
-- 守门①:本 V23 同时放仓根 contracts/db-schemas/(授权源)+ huijing-server 执行目录(唯一执行副本),
-- 不放任何单模块 -server/db/migration/(避免同版本出现在多个 classpath jar 触发 Flyway 重复校验失败)。
-- 守门②:含中文 SQL,mini-desktop 执行必须 --default-character-set=utf8mb4(防乱码)。
-- 约定:InnoDB + utf8mb4;显式列 + 列级中文 COMMENT;状态机用 TINYINT,非法流转由 Service 校验、DO 层不承载;
-- 每表强制 Yudao 6 审计列(creator / create_time / updater / update_time / deleted BIT(1) / tenant_id BIGINT,全 NOT NULL,MVP 单租户 tenant_id=0);
-- 归属隔离列 user_id / creator_user_id 由 Mapper 强制以 getLoginUserId() 作 WHERE 谓词 enforce(可信边界,非 @DataPermission);禁裸 select*。
-- 错误码段:community = 1-107-***-***(落 -api 的 ErrorCodeConstants.java,评论 004/关注 005/排行 006/弹幕 007)。
-- 幂等:关注 uk(user_id,target_user_id,deleted,tenant_id) 软切换不删行;排行 uk(dimension,target_id,deleted,tenant_id) 一目标一行。
-- =============================================================================
-- -----------------------------------------------------------------------------
-- 表1:game_community_comment —— 评论(CRUD + 举报转 compliance)
-- 归属隔离 = Mapper 删除/编辑强制 user_id = getLoginUserId() 谓词,用户只能改自己的评论;
-- 列表查询按 target_type+target_id 维度(公开可见,不按 user 隔离)。举报由 Service 落举报态 + 转 compliance 受理(事务提交后)。
-- -----------------------------------------------------------------------------
CREATE TABLE `game_community_comment` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '评论 ID',
`target_type` TINYINT NOT NULL DEFAULT 1 COMMENT '评论目标类型:1游戏(MVP 仅游戏,预留扩展)',
`target_id` BIGINT NOT NULL COMMENT '评论目标 ID(target_type=1 时 = game_project.id)',
`user_id` BIGINT NOT NULL COMMENT '评论作者用户 ID(归属隔离:删除/编辑 Mapper 强制以 getLoginUserId() 作 WHERE 谓词)',
`content` VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '评论正文',
`parent_id` BIGINT NOT NULL DEFAULT 0 COMMENT '父评论 ID(0=一级评论;预留楼中楼,MVP 不展开树)',
`report_status` TINYINT NOT NULL DEFAULT 0 COMMENT '举报态:0正常 1被举报(转 compliance 受理后置 1,本端只留信号痕迹,不裁决)',
`creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列;区别于业务归属列 user_id)',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除:0未删 1已删',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID(MVP 单租户=0)',
PRIMARY KEY (`id`),
KEY `idx_target` (`target_type`, `target_id`, `id`) COMMENT '目标维度评论列表(按 id 倒序,新评论在前)',
KEY `idx_user` (`user_id`, `id`) COMMENT '我的评论列表 / 归属校验加速'
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '社区评论(CRUD + 举报转 compliance,U3 R-SOC)';
-- -----------------------------------------------------------------------------
-- 表2:game_community_follow —— 关注(active 软开关幂等切换,不删行)
-- 范本 = feed game_feed_interact_log:唯一键命中则改 active(取关=反激活 active=0),未命中则插,幂等不重复落行。
-- 计数 = countActive(active=1)。一对 (user_id,target_user_id) 一行(uk 保证幂等,反复关/取关只切 active)。
-- -----------------------------------------------------------------------------
CREATE TABLE `game_community_follow` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '关注关系 ID',
`user_id` BIGINT NOT NULL COMMENT '关注发起方用户 ID(粉丝;归属隔离:写动作强制以 getLoginUserId() 承载)',
`target_user_id` BIGINT NOT NULL COMMENT '被关注方用户 ID(偶像)',
`active` TINYINT NOT NULL DEFAULT 1 COMMENT '激活态:1已关注 0已取关(软开关,取关不删行)',
`creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_target` (`user_id`, `target_user_id`, `deleted`, `tenant_id`) COMMENT '一对关注关系一行(幂等软切换,防并发双插)',
KEY `idx_target_active` (`target_user_id`, `active`) COMMENT '粉丝数统计(某人被多少 active 关注)',
KEY `idx_user_active` (`user_id`, `active`) COMMENT '关注数统计 / 我的关注列表'
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '社区关注关系(active 软开关幂等,U3 R-SOC)';
-- -----------------------------------------------------------------------------
-- 表3:game_community_rank —— 排行权威源(DB=真相,Redis ZSET=缓存索引)
-- 一致性窗口(最终一致):分值变更事件在同一 Service 流程内【双写】DB 本行 + ZSET(写穿透);
-- ZSET 缺失/启动/周期对账时由本表回填重建 ZSET(rebuild)。score 落 DB 供权威回填,ZSET 仅供快速 TopN。
-- 一目标一维度一行(uk 保证幂等累加落点)。
-- -----------------------------------------------------------------------------
CREATE TABLE `game_community_rank` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '排行记录 ID',
`dimension` VARCHAR(32) NOT NULL COMMENT '排行维度(如 game_hot 游戏热度 / creator_hot 创作者热度),与 ZSET key community:rank:{dimension} 对应',
`target_id` BIGINT NOT NULL COMMENT '排行对象 ID(game_hot=gameId / creator_hot=creatorUserId)',
`score` BIGINT NOT NULL DEFAULT 0 COMMENT '排行分值(权威源;BIGINT 防溢出,与 ZSET double 同口径取整数域)',
`creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(系统身份写=0)',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者(系统身份写=0)',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_dimension_target` (`dimension`, `target_id`, `deleted`, `tenant_id`) COMMENT '一维度一对象一行(幂等累加落点 + ZSET 回填唯一源)',
KEY `idx_dimension_score` (`dimension`, `score`) COMMENT '权威排序回填 TopN(ZSET 重建用)'
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '社区排行权威源(ZSET 回填源,U3 R-SOC)';
-- -----------------------------------------------------------------------------
-- 表4:game_community_danmaku —— 弹幕(WebSocket 广播 + 落库可回放)
-- 房间 = game_id(同一游戏的所有在线观众)。发送 = 落库 + WebSocket 广播给房间内会话。
-- 多实例边界:本波 LocalWebSocketMessageSender 仅单机;多实例需切 huijing.websocket.sender-type=redis(MQ future-state 未部署)。
-- -----------------------------------------------------------------------------
CREATE TABLE `game_community_danmaku` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '弹幕 ID',
`game_id` BIGINT NOT NULL COMMENT '游戏 ID(= game_project.id,弹幕房间维度)',
`user_id` BIGINT NOT NULL COMMENT '发送者用户 ID',
`content` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '弹幕正文',
`play_time` INT NOT NULL DEFAULT 0 COMMENT '播放进度(秒;回放时按此对齐弹幕出现时机,MVP 可为 0)',
`creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID',
PRIMARY KEY (`id`),
KEY `idx_game` (`game_id`, `id`) COMMENT '某游戏最近弹幕回放(按 id 倒序/正序取近段)'
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '社区弹幕(WS 广播 + 落库回放,U3 R-SOC)';