社区社交后端四子能力(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>
108 lines
10 KiB
SQL
108 lines
10 KiB
SQL
-- =============================================================================
|
||
-- 契约 #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)';
|