当前位置: 首页 > news >正文

山海万灵 HarmonyOS 文化知识实战(21):CMS 内容版本、审核、发布与回滚工作流

神兽条目、来源校注和数字馆长讲解都会持续修订。CMS 若只保存“当前内容”,编辑后的标题、摘要或来源一旦覆盖旧值,就难以回答线上内容从哪个版本发布、谁审核过、如何恢复到可信版本。山海万灵把内容快照、审核任务、发布任务和 Outbox 事件拆开保存,让每次状态变化都能沿着版本号回读。

先把内容版本和公开状态分开

内容项保存当前版本与已发布版本,版本表保存不可变的快照。审核、发布和回滚不直接把编辑区的字段写入公开投影,而是先定位到一个明确的版本。这样可以在同一条目上继续编辑 v3,同时让读者侧仍然读取已发布的 v2。

对象负责的信息为什么独立保存
内容项当前版本、已发布版本、生命周期状态给列表和运营页提供稳定摘要
内容版本标题、摘要、来源键与来源校注快照让历史内容可比较、可恢复
审核任务提交人、审核状态、审核意见把“可发布”变成明确门禁
发布任务目标版本、执行状态、发布时间同一版本重复提交时保持幂等
Outbox 事件事件类型、内容版本、投递状态让下游投影异步消费而不丢失业务事实

生命周期并不把所有状态压进一个枚举。内容可以处于reviewing,发布任务可以处于pending,Outbox 则仍是pendingdelivered。三个状态各自回答不同问题:内容能否被审核、发布动作是否已提交、下游是否已经收到事件。

public record ContentItem( String id, String type, String status, int currentVersion, Integer publishedVersion, String title, String summary, String sourceKey ) { } public record ContentVersion( long id, String entityType, String entityId, int versionNo, String snapshotJson ) { }

版本快照同时保留来源校注的关键字段。发布边界不会仅凭“审核通过”放行:来源型内容还要具备已校注的版本、页码、审核人和审核时间。这个限制避免后续修改来源记录时反向改变已经审核过的历史版本。

审核门禁先于发布任务

审核接口接收内容类型、内容标识和版本号,服务层会先确认内容与版本存在,再创建或复用处于reviewing的任务。审核通过后,发布者才能为同一版本创建发布任务;审核员角色不能越过这个边界直接发布。

public ReviewTask submitReview(ReviewSubmission request) { ContentContext context = requireContentVersion( request.entityType(), request.entityId(), request.version()); ReviewTask existing = repository.findActiveReviewTask(context.version().id()); if (existing != null) { return existing; } return repository.createReviewTask( newId("review"), context.content().type(), context.content().id(), context.version().id()); } public PublishJob createPublishJob(PublishRequest request) { ContentContext context = requireContentVersion( request.entityType(), request.entityId(), request.version()); requireApprovedReview(context.version().id()); requireAnnotatedSourceForPublish(context.type(), context.version()); return repository.findPublishJob(context.type(), context.id(), context.version().id()) .orElseGet(() -> repository.createPublishJob(newId("publish"), context)); }

来源校注尚未冻结在版本快照中时,发布任务会返回业务错误,不生成 Outbox。这个顺序比“先发布、再补来源”更可靠:公开内容只有在版本、审核和来源条件同时满足时才跨过边界。

发布只提交一个事务事实

执行发布任务时,CMS 在同一事务内更新内容项的已发布版本、标记任务成功,并写入content.published事件。事务提交完成后,内容服务再消费事件,刷新公开投影、缓存和检索索引。发布接口返回的是 CMS 已完成的任务和待投递事件,不把异步下游处理伪装成同步完成。

@Transactional public PublishExecution executePublishJob(String jobId) { PublishJob job = repository.requirePendingJob(jobId); ContentContext context = requireContentVersion( job.entityType(), job.entityId(), job.versionNo()); requireApprovedReview(context.version().id()); requireAnnotatedSourceForPublish(context.type(), context.version()); repository.markContentPublished(context.id(), context.version().versionNo()); repository.markPublishJobSucceeded(job.id()); String eventId = "event-publish-" + job.id(); repository.insertOutboxEvent(eventId, "content.published", context.type(), context.id(), eventJson(context, eventId)); return completedExecution(job, eventId); }
情况工作流结果页面与下游处理
未审核版本请求发布返回CMS.PUBLISH_NOT_APPROVED不创建发布任务,不写事件
来源校注不完整返回来源校注错误继续停留在审核或修订阶段
同一版本重复创建任务返回已有任务不重复生成版本或事件
任务成功、投递尚未完成发布状态成功,事件待投递Outbox 负责后续重试与追踪

这种拆分适合 CMS 的长链路操作。编辑页只处理内容与审核动作,公开投影只处理已发布事件;缓存、搜索与媒体服务不会被塞进同一个 HTTP 请求里。

冲突和投递失败都保留在状态机里

发布任务创建后,编辑者仍可能继续修改内容。执行任务前服务会再次核对目标版本、审核状态和发布任务状态;版本号已经变化时返回版本冲突,而不是把旧任务覆盖到新内容上。审核被撤销、来源校注被移除或任务已经执行时,同样不能继续写入公开状态。

Outbox 的失败也不应折叠成“发布失败”四个字。CMS 事务成功后,发布任务保持成功,事件保留待投递或失败原因;投递器可以按事件标识重试。这样运营人员能够区分三种情况:内容尚未达到发布门禁、CMS 尚未提交业务事件、下游投影暂时没有消费事件。三者的修复入口、重试条件和审计责任不同。

异常服务端保护恢复方式
版本已被新编辑替换返回版本冲突,不更新已发布版本重新选择当前版本并发起审核
审核或来源条件失效拒绝创建或执行发布任务补齐审核、校注后重新创建任务
事件投递暂时失败保留 Outbox 记录与失败状态由投递器按事件标识重试
回滚目标缺少完整快照拒绝恢复,不制造不完整公开内容选择具备完整来源快照的历史版本

端侧只消费已经公开的内容投影,后台版本、审核和发布状态仍由 CMS 服务维护。需要为 HarmonyOS 阅读体验保存本地副本时,可参考 OpenHarmony 的关系型数据库应用指南,把本地缓存与后台发布审计保持为两个独立边界。

回滚生成新版本,而不是覆盖历史行

内容纠错通常不是简单地把正文改回去。神兽名称、摘要、来源键和来源校注必须来自同一份历史快照,才能避免正文恢复了、关系或出处却仍停留在新版本。回滚接口要求目标版本小于当前版本,并把目标快照复制成一个新的发布版本。

@Transactional public RollbackExecution rollback(RollbackRequest request) { ContentItem current = repository.requirePublishedOrOffline(request.entityId()); ContentVersion target = repository.requireVersion( request.entityType(), request.entityId(), request.targetVersion()); requireAnnotatedSourceForPublish(request.entityType(), target); int nextVersion = current.currentVersion() + 1; PublishJob existing = repository.findRollbackJob( request.entityType(), request.entityId(), target.id()); if (existing != null) { return rollbackExecution(existing, target.versionNo()); } PublishJob job = repository.createRollbackVersionAndJob( current, target, nextVersion, request.reason()); repository.insertOutboxEvent("event-rollback-" + job.id(), "content.rollback", request.entityType(), request.entityId(), rollbackEventJson(nextVersion, target.versionNo())); return rollbackExecution(job, target.versionNo()); }

回滚事件同时携带新contentVersionrestoreFromVersion。内容服务使用新版本做乱序保护,再以恢复来源快照重建公开内容;同一回滚请求再次到达时会复用已有任务。这让 v1、v2、v3 都保留在历史中,其中 v3 可以恢复 v1 的可信内容,而不会抹掉 v2 的修改记录。

版本差异只暴露运营所需字段

版本差异接口按内容类型、内容标识和两个版本号比较titlesummarysourceKey。接口返回结构化差异,不返回原始snapshotJson。发布者可以确认将要发布或回滚的业务差异,原始快照与来源细节仍留在受控服务边界内。

CMS 工作流服务的 19 项回归与 HTTP 契约的 6 项回归均通过;运行中的 CMS 健康接口返回 HTTP 200。回归覆盖审核与角色边界、已校注来源门禁、幂等发布任务、Outbox 事件、下线以及把历史快照恢复为新发布版本的回滚路径。

可观察的验收链路

  1. 为一个内容项创建新版本并提交审核,重复提交时确认仍返回同一审核任务。
  2. 以审核员完成审核,再以发布者创建并执行发布任务,检查任务状态与 Outbox 事件标识。
  3. 对缺少校注版本、页码或审核时间的来源重复发布操作,确认服务拒绝创建发布任务。
  4. 选择较早的完整版本执行回滚,回读新的当前版本、已发布版本与恢复来源版本。
  5. 重新提交同一回滚目标,确认系统复用已有回滚任务,历史版本数量不重复增长。

事务边界与事件投递采用 Spring 的声明式事务模型;具体的事务传播和回滚规则可参阅 Spring Framework 事务文档。

http://www.jsqmd.com/news/1356178/

相关文章:

  • 鹰潭球墨铸铁树围篦子厂家/球墨铸铁篦子源头厂家哪家强 - 企业推荐官-
  • 2026年宋雪萍律师 宁波靠谱企业法律顾问服务评测 - 起跑123
  • 2026年呼伦贝尔诚信的包车游旅行社真实游玩体验分享 - 起跑123
  • 2026 年 7 月新发布:达县诚信的双向止水铸铁闸门制造厂家怎么联系,用了这玩意儿,河道水利的渗漏难题竟能直接解决? - 行业推荐官【认证】
  • 电磁夹爪选型维度与2026年主流电磁夹爪品牌盘点 - 品牌深度评测
  • Isaac Lab 方法原理 - S-X
  • KKCE: 基于网站测速的 HTTP/2 优先级树反转与伪并行阻塞分析-快快测
  • 2026年微型无刷风机厂家哪个好 实测多款无刷风机性能 - 奔跑123
  • 2026 年淮阴专业的翅片式冷凝器生产厂家联系电话,为啥你家空调制冷总不给力?原来藏在机器里的这玩意儿早该换了!-宇航机械 - 企业信息推荐-2
  • 2026年找热风干燥机优质厂家,这份指南别错过 - 奔跑123
  • 2026年浙江专业PVC卷带定制 永丽装饰值得选择 - 奔跑123
  • 2026 年现阶段,贺州值得关注的回收硫酸铜销售厂家格局重塑与选型新思路,那些被丢弃的蓝色粉末,居然能帮你省下一大笔原料钱? - 企业官方推荐【认证】
  • AI时代开源安全新威胁:模型社会工程学攻击原理与防御实战
  • 哈尔滨快递打包机厂家/全自动快递打包机厂家电话-银铃智能科技 - 企业推荐官【认证】
  • 考公
  • 电爪品牌推荐评估维度有哪些?2026年主流电爪品牌盘点 - 品牌深度评测
  • 2026年微型无刷风机厂家选哪个好 宁波东莱机电无刷风机评测 - 奔跑123
  • 2026青岛系统门窗厂家实力**测评 - Gsydold
  • 2026 年更新:吴中评价高的家用磁悬浮室内移门品牌有哪些,家里装了这玩意儿,我终于不用再忍受推拉门的刺耳噪音了 - 行业严选官
  • 2026年国内龙门加工中心实力品牌梯队梳理 - 起跑123
  • 2026年有什么小程序可以把照片转成拼豆图纸?亲测好用的免费方法 - 软件测评小帮手
  • 宜春水下打捞救援队|打捞潜水队施工团队哪个好 - 企业信息推荐-2
  • 2026 年现阶段,英山比较好的厂房外墙彩绘服务团队怎么联系,这面工厂外墙竟成了网红打卡点?全靠这不起眼的手绘手艺 - 行业严选官
  • 2026 年至今,深州有实力的道路防撞护栏供货厂家哪家专业,花了几十万装的这玩意儿,关键时刻能救命?谁告诉你它只能挡车? - 领域鉴赏官
  • 2026年热风干燥机优质厂家推荐不妨了解下宁波斯丹德 - 起跑123
  • 2026年想找宁波靠谱玻璃钢加工厂哪家好?选迈斯特凡博 - 奔跑123
  • 2026年宁波靠谱粉尘处理设备厂家选购指南分享 - 奔跑123
  • 2026年微型无刷风机厂家哪个好 宁波东莱机电无刷风机评测 - 奔跑123
  • 国开学位英语 零基础逐周备考计划(目标 2026-11,每天3小时)
  • 机器人夹爪的选型技巧是什么?2026年实力型机器人夹爪品牌推荐 - 品牌深度评测