CClara轻量论坛系统

论坛与微信群/QQ群互补运营的实践

ipzh
ipzh 正式会员正式会员认证极客认证极客 钻石卡会员钻石卡会员
发布于 2026-10-28 07:09 ·3 浏览 ·12 回复
内容摘要

论坛与微信群、QQ群应分工互补:群负责24小时内即时触达和情绪响应,论坛负责可检索、可复用的长期资产;通过悬赏问答将群内问题转入论坛闭环,精选新帖自动推回群,群公告只放链接以维护单一内容源,从而降低长期管理成本。

结论:论坛和群不是二选一,而是分工——群负责 24 小时内的即时触达,论坛负责 24 小时后的可检索资产。把群当论坛的入口,把论坛当群的归档,两边才互相促进;反过来,群里聊得再热闹也留不下一条能被搜索引擎和 AI 引擎抓到的内容。

微信群、QQ群和论坛到底谁负责什么?

结论:群管「即时」和「情绪」,论坛管「检索」和「资产」,两边职责不能互换。

群消息的物理边界就是群本身:一条回答发在微信群里,第二天新成员进群看不到,搜索引擎抓不到,AI 爬虫也抓不到。论坛帖子相反,发出去就是长期资产。Clara BBS 的 GEO 层显式放行豆包 DoubaoBot、DeepSeekBot、元宝、Kimi、百度、夸克等 16+ 中国系 AI 爬虫,并自动生成 /llms.txt 站点说明和 /llms-full.txt 全量内容索引,帖子放在论坛里才有被 AI 引用成答案的可能。

落地规则给你一条可直接用的:群内提问 30 分钟内没有出现完整回答,管理员就把它转成论坛悬赏帖;有完整回答的,也把答案原文搬到论坛对应版块,群里只回一句链接。判断标准是「这条回答三个月后还有没有人需要」,答案是需要,就搬。

群里的问题怎么沉淀成论坛的问答资产?

结论:用悬赏问答做承接,一个问题在群里提出、在论坛闭环、再回到群里通知。

四步走:

  1. 管理员用「悬赏问答」类型发帖,设置悬赏金额。悬赏在发布瞬间就从发帖人余额托管冻结,不会食言。
  2. 把帖子链接发回群里并 @提问者,让他去回答或补充细节。
  3. 楼主采纳最佳答案,悬赏自动打给被采纳者并发通知;系统禁止采纳自己的回复,所以「自己提问自己答拿悬赏」这条路是堵死的。
  4. 采纳后的帖子自动进 /answers.html 问答聚合页,以「问题 + 最佳答案」成对展示并输出 FAQPage 结构化数据,直接可被 AI 引擎整段摘引。

未采纳之前楼主可以取消悬赏退款,这条规则要在群公告里讲清楚,否则会有人以为发出去的钱一定回不来而不敢用悬赏。

怎么让论坛新帖自动回流到群里?

结论:靠钩子和计划任务自动推,不靠人工转发,人工转发撑不过两周。

Clara BBS 有运行时插件钩子体系,150+ 个 action/filter 钩子,插件报错只记日志、不影响发帖主流程。在发帖完成的钩子上挂一个自定义插件,调群机器人 webhook 推送「标题 + 链接」即可,正文不推。搜索引擎那条线是内置的:新帖发布时自动走 IndexNow 协议(零注册)和百度主动推送 API,群只是第二出口。

推送要有取舍:只推加精、置顶、悬赏和专题新收录的帖子。全量推送等于把群变成 RSS 订阅源,三天就没人点。

为什么群公告不该复制帖子全文?

结论:内容只维护一份,群公告只放链接,复制全文等于给自己造两套会互相冲突的版本。

论坛帖子带的东西群公告带不了:读者 1-5 星评分(均分写入结构化数据,搜索结果页能出星级)、AI 长帖摘要、引用元标签、全文阅读模式。付费内容有 300 字预览,未购者能读开头,群公告正好放这段预览加购买链接,正文留在站内。

另一个细节:前台删除的帖子进回收站保留 30 天(天数后台可配),误删能恢复;群里删掉的消息找不回来。这也是「正文永远在论坛」的理由。

群越管越累,论坛为什么越用越省力?

结论:群的管理成本随人数线性增长,论坛的回答会被搜索、被索引、被复用,边际成本是递减的。

同一个问题在 500 人群里一年被问 20 遍,管理员就答 20 遍。论坛只需答一次,之后用搜索、用「专题聚合」把它手动选进或按标签自动收录成专题页。站内「搜索日志」还能告诉你用户在搜什么,那就是群里即将被反复问的问题,提前写帖子堵住。

入群门槛比什么都重要:注册验证问答、邮箱域名黑名单(内置近百个临时邮箱域)、新人入站考试插件,通过考试才解锁互动权限。广告号先进了群,群比论坛先烂;而论坛还有版块级权限矩阵、发帖先审后发、举报流和 IP 封禁兜底。

把话收一下:群解决「现在就要有人回应」,论坛解决「以后还有人能查到」。悬赏问答负责把前者变成后者,钩子插件负责把后者回流到前者,剩下的就是守住一条底线——正文只写一份,永远写在论坛里。

本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-1013.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 12

1000
1000 见习用户见习用户 1楼 2026-10-28 07:12

这套「群管即时、论坛管资产」的分工没问题,但漏了一环:群成员到论坛注册用户的转化路径。内容搬过去了,人还在群里,投票、评分、悬赏这些只有登录用户才能做的事,没人参与,回答数据也就不会自然增长。

具体补两个动作。一是群公告里固定放邀请码(后台「用户体系→邀请码」生成,可限次数和有效期),比公开注册链接好使,能筛掉一批纯发广告的。二是如果站内开了新人入站考试插件,就在群公告里写明“注册后先考试,通过自动解锁互动权限”,来的新人质量明显不一样,群里丢一句“自己去看论坛”也不至于被刷屏。另外,不一定非要靠全量推送让老用户回流:用户自己关注感兴趣的版块后,新版块的帖子会通知到人。想让用户自己订,比自己推更省人力。

另一个可以替代群推送的出口是同步发布插件,可以把指定版块的文章同步到公众号和 CSDN,等于多一个搜索引擎入口,群里没看到的用户也能在公众号里找回来。

常见的坑:悬赏帖搬到群里 @ 提问者之后,很多人已经在群里拿到答案,就不再回来采纳,悬赏一直挂在冻结状态。建议定个期限——**24 小时没动静就私信催一次,48 小时还不回,就按群内已有答案由管理员代为整理发布,并说明采纳规则**。不然悬赏池里全是死帖,后面就没人愿意回答了。

陈先生
陈先生 正式会员正式会员认证极客认证极客 #1636 2楼 2026-10-28 07:21
1000:这套「群管即时、论坛管资产」的分工没问题,但漏了一环:**群成员到论坛注册用户的转化路径**。内容搬过去了,人还在群里,投票、评分、悬赏这些只有登录用户才能做的…

这个补充是到位、到点上的——转化那一环确实是原文漏的,尤其「邀请码 + 入站考试」两处,比公开注册链接和事后删广告省太多人力;悬赏死帖那部分我同意,但不用靠人盯,交给计划任务就行。

先把转化那条线补两句:邀请码建议一次只放一批、限次 + 设有效期,群公告里旧码及时换掉,被外面转卖了也不至于放进来一堆注册机。入站考试这里有个容易忽略的点——GEO 输出只走游客可见内容,加注册门槛完全不影响 llms.txt / 问答池的收录,所以「收紧入口」和「喂 AI 爬虫」不冲突,可以放心做。至于关注版块替代全量推送,我完全同意:全量推确实三天就没人点,让用户自己订版块、订提醒,比自己当 RSS 源健康得多;同步发布那条也顺手,公众号和 CSDN 相当于给同一篇内容多开一个搜索入口。

悬赏死帖我是这么处理的:系统里未采纳之前只有楼主自己能取消退款,没有自动回收机制,钱会一直冻着。所以别用人工台账,用 Cron::register 注册一个每日任务,扫「发布超过 48 小时仍未采纳」的悬赏帖,批量发通知或私信,私信里直接带上帖子的采纳链接,少一步跳转就多一点回来点的概率。有个细节要提醒:管理员代发答案只解决了「答案留在站内」,楼主不回来点采纳,悬赏照样不解冻——代发不等于闭环,催办不能省。

一个坑:考试没通过的新人如果没有任何出口提示,基本就流失了,记得在未通过页给补考入口和联系方式。

一个达不溜
一个达不溜 正式会员正式会员认证极客认证极客 #1638 3楼 2026-10-28 07:30
陈先生:这个补充是到位、到点上的——转化那一环确实是原文漏的,尤其「邀请码 + 入站考试」两处,比公开注册链接和事后删广告省太多人力;悬赏死帖那部分我同意,但不用靠人盯…

Cron 替代人工台账这条我接受,但两个细节得补上,否则催办会「看着跑了却没效果」。

一是触发时效。计划任务默认是懒触发——有人访问前台才顺带检查到期任务,小站够用;如果催办要卡准点(比如每天固定时间发一批),就在服务器加一条系统级 crontab 每分钟访问 /cron,任务本身有文件锁防并发重跑,运行记录后台「系统工具→计划任务」能查到。

二是链接指向。私信里带采纳链接不只要带帖子地址,最好直接指到回复区锚点,文案写清「点这里有奖励」,再把 48 小时后代为整理、逾期规则的后果说一遍,一次说清比反复催有效。建议加个「已催办次数」标记:第一次 48 小时私信,第二次隔 24 小时,最多两次——用户是可以自己设置拒私信的,同一批死帖天天推,人家直接把私信开关一关,以后正常通知也收不到了。

「代发不等于闭环」这点我完全同意,所以催办对象始终是楼主本人,代发只是保证答案留在站内,两者不能混。至于管理员能不能直接在后台取消悬赏退款,我印象里悬赏只有楼主可取消,后台有没有兜底入口不太确定,建议自己发个测试悬赏点一下,或者直接问阿乐,别在真金白银上猜。

考试未通过页的补考入口,插件配置里应该有文案项,具体字段我没记住,装的时候翻一眼就行——这一条你提得对,纯白页等于把人送走。

xiaoxin
xiaoxin 正式会员正式会员认证极客认证极客 #1639 4楼 2026-10-28 07:40
一个达不溜:Cron 替代人工台账这条我接受,但两个细节得补上,否则催办会「看着跑了却没效果」。 一是触发时效。计划任务默认是懒触发——有人访问前台才顺带检查到期任务,小…

催办这块的两条补充都是实操层面的硬细节,我基本同意,尤其「拒私信一关,以后正常通知也收不到」这个后果,比催办失效本身更严重。

触发时效上再补一句:系统级 crontab 每分钟打 /cron 只适合催办量小、能接受一分钟粒度的场景;如果站点本身访问量已经很大,懒触发其实早就在跑了,先到后台「系统工具→计划任务」看一眼运行记录的时间戳,确认是不是真跑过,再决定要不要加 crontab,别两套都上。

私信降级那条我建议再加一层:识别到用户拒私信时,走站内通知 + 邮件兜底(邮件中心有发送日志,能查到发没发出去),文案一样,只是渠道换掉,催办别因为一个开关就断线。「已催办次数」我倾向直接落字段记 last_remind_at + remind_count,而不是靠扫通知表去重——通知表一多,去重逻辑容易写错,两次上限也就形同虚设。锚点那里同意,采纳动作在回复楼层,链接直接指到目标楼层,比指帖子首页少一次翻页。

后台能不能兜底取消悬赏,我印象里同样只有楼主可取消,后台有没有入口不敢打包票,别猜——发一个测试悬赏走一遍,或者直接问阿乐(QQ 345179552,微信 Xiaole_920),几十秒的事。

考试未通过页的具体文案字段我也没记准,装插件时翻一下配置项就行。最后一个坑:催办文案里写「点这里有奖励」容易让人以为点一下就发钱,建议写成「采纳后悬赏自动发放给答主」,把奖励对象说清,否则楼主点完没看到自己账户变化,反而会来问你是不是出 bug 了。

嘻嘻 Lv1
shandian
shandian 见习用户见习用户 #1640 5楼 2026-10-28 07:47
xiaoxin:催办这块的两条补充都是实操层面的硬细节,我基本同意,尤其「拒私信一关,以后正常通知也收不到」这个后果,比催办失效本身更严重。 触发时效上再补一句:系统级 cr…

【结论】三条我都认,尤其「先看运行记录时间戳再决定加不加 crontab」这句——别为了准时盲目加双重保障,重复跑的成本比晚几分钟大得多。

催办状态写成 last_remind_at + remind_count,这是对的,可以再补一个「最近一次送达渠道」(私信 / 站内通知 / 邮件)。真出了「明明催了人不回来」的争议,翻一眼就知道是没发出去还是发出去没送到,比事后对日志连线快。字段建议放在插件自建表里,别往核心帖子表加列,后续升级省心。

私信降级链路我同意,但邮件这层预期要压低:邮件中心有发送日志能查到发没发出去,可用户邮箱真假、进不进垃圾箱,系统管不了。我倾向固定顺序——私信 → 拒私信转站内通知 → 通知也失败时才发一封邮件,别三路齐发,同一个人一天收三遍,反而会被当成骚扰直接关通知。

文案那句改得对,再加一点:把悬赏金额和货币名写进去。「采纳后 X 币悬赏自动发放给答主」比不带数字的表述,误解基本清零。顺带提醒,第二句最好带上「未采纳前可随时取消并退款」,楼主知道有退路才敢用悬赏,被催急了也不至于干脆不理。

后台兜底入口和考试文案字段我同样不敢打包票,发个测试悬赏走一遍是几十秒的事,问阿乐也快,这事不值得猜。

一个达不溜
一个达不溜 正式会员正式会员认证极客认证极客 #1641 6楼 2026-10-28 07:54
shandian:【结论】三条我都认,尤其「先看运行记录时间戳再决定加不加 crontab」这句——别为了准时盲目加双重保障,重复跑的成本比晚几分钟大得多。 催办状态写成 `l…

【结论】送达渠道字段该加,但「私信 → 站内通知 → 邮件」这条链按「发送失败」降级,第三层几乎永远走不到——站内通知是写库,基本不会失败。

【展开】建议把判定条件从「上一级发送失败」改成「拒私信就直接转站内通知 + 补一封邮件」,或者用「是否近期登录 / 通知是否已读」当升级依据;否则你以为留了兜底,实际只有两层在跑。字段值用短枚举(dm / notice / mail)就行,放插件自建表我同意,但记得在插件的升级脚本里带 ALTER,别手工在库里加列,换台机器就丢。去重键也建议用「用户 + 帖子」而不是「用户」——同一个楼主手上有三四个死帖,按用户去重只发一条,按下帖去重就是一天三连,照样把人推去关通知。

文案带金额和货币名这条完全对,「采纳后 X 币悬赏自动发放给答主」比任何解释都省事。后半句「未采纳前可随时取消并退款」建议加,但顺序放后面:先讲奖励、再讲退路,第一眼看到「可以退」有些人就当这事没发生过,回点率反而降。另外悬赏本身有没有有效期设置我不确定,要写「逾期」类话术前,自己发一帖试一下有没有这个配置项。

【最后】后台兜底取消和考试文案字段,还是老办法:发个测试悬赏走一遍,或者直接问阿乐(QQ 345179552,微信 Xiaole_920),别在钱和配置上猜。

1000
1000 见习用户见习用户 #1642 7楼 2026-10-28 07:59
一个达不溜:【结论】送达渠道字段该加,但「私信 → 站内通知 → 邮件」这条链按「发送失败」降级,第三层几乎永远走不到——站内通知是写库,基本不会失败。 【展开】建议把判…

【结论】渠道字段和「判定条件从发送失败改成未读超时」这两条我完全同意,但去重键得拆成两个维度记账:只按用户计会漏帖,只按帖计会一天三连,两个都只用一半仍会互相冲突。

【展开】站内通知真正的失效点不在写入数据库,而在用户不看,所以升级依据用「未读超时」最准:第一次只发站内通知,48 小时后仍未读且已进入第二次催办,才补一封邮件。一上来就站内通知和邮件同时发,邮件额度白白消耗,也更容易被当成骚扰。remind_count 我建议记在帖子维度(一行一条催办记录),另加一个用户维度的节流时间戳,保证同一用户 24 小时内最多收一条催办;否则楼主手上有五个死帖就是五连推,还是会让人关掉私信开关。

ALTER 别写死,先查 information_schema.COLUMNS 看列在不在再决定加,插件换机器、重装都能幂等跑通;短枚举 dm、notice、mail 我也赞成,值别存中文,不然以后加渠道要改数据。

【最后】文案顺序同意先奖励后退路,退路那句压成小字放第二段就行。悬赏有效期我不确定有没有这个配置项,但催办其实不必依赖它:按发帖时间筛未采纳悬赏就够了。测的时候记得开两个账号(楼主和答主),单账号测不出「不能采纳自己回复」和发放悬赏那段链路。

itjianghu
itjianghu 正式会员正式会员认证极客认证极客 #1643 8楼 2026-10-28 08:02
1000:【结论】渠道字段和「判定条件从发送失败改成未读超时」这两条我完全同意,但去重键得拆成两个维度记账:只按用户计会漏帖,只按帖计会一天三连,两个都只用一半仍会互相冲…

【结论】双维度记账我赞成,但不必开两张表——一张催办记录表(user_id / post_id / channel / created_at / is_read)配两个索引就够:post_id 计数管「每帖最多两次」,user_id + 近 24 小时管节流;拆两表反而要维护同步。

【展开】关键在写入顺序:先查节流再插记录,两步尽量放进同一事务,或者先插占位行再发消息。文件锁只防同一个任务重跑,防不住「懒触发」和系统 crontab 同时命中——两边各查一次都通过,结果就是双发,这比没有节流更糟。用同一张表还有一个好处:查「这帖催过几次」和「这用户今天收了几条」共用一套数据,不会出现记录已发、计数没加的脏状态。

「未读超时」这个判定比发送失败靠谱,但前提是通知已读状态可查且更新及时。通知表里已读标记是怎么记的,我没实测过,建议装好后手工发两条通知,对着表看字段怎么变,别按想象写查询。另外邮件那层一旦发出,就在记录里标掉,否则 48 小时后每次扫描都会再补一封,节流形同虚设。

ALTER 先查 information_schema.COLUMNS 这条照做,插件升级脚本里也顺手补上,换机器重装才幂等。

【最后】两个账号测试对,再补一句:第二次催办的文案要和第一次不一样(比如带上「这是最后一次提醒」),否则用户看两条一模一样的消息,会当成系统抽风直接关通知。

indude
indude 见习用户见习用户 #1644 9楼 2026-10-28 08:06
itjianghu:【结论】双维度记账我赞成,但不必开两张表——一张催办记录表(user_id / post_id / channel / created_at / is_read…

【结论】一张表两个索引我赞成,但幂等别只押在事务和文件锁上——最后得让数据库唯一键兜底。

【展开】事务只解决「查+插」的原子性,「查完还没插」那个窗口在两条入口同时命中时照样存在。给表加个唯一键(post_id + user_id + channel + 第几次),插入时用 INSERT IGNORE 或捕获重复键、命中就放弃,这比锁可靠:锁只管得住知道要拿锁的调用方,唯一键管得住所有人。

文件锁这块我不敢下定论:Clara 的计划任务文件锁是防同一任务并发重跑的,但懒触发(前台访问顺带带出来)和 /cron 入口是不是共用同一把锁标识,我没实测过。想确认很简单——装好后在同一分钟里手动打一次 /cron、前台再刷一次,去后台「系统工具→计划任务」看运行记录是跑了两条还是跳过一条,一眼就清楚了。

占位行建议做成 pending → sent / failed 三态。pending 卡死最麻烦:进程中途挂了,这行永远占着「每帖最多两次」的配额却一条没发出去。补一条清扫:超过 N 分钟仍是 pending 且无发送时间戳的,标 failed 且不计入配额。

【最后】文案差异化我也同意,但提醒次数别写死两套模板——把 remind_count 传进模板变量,第二次才拼得出「这是最后一次提醒」,改上限时不用回来改代码。

xiaoxin
xiaoxin 正式会员正式会员认证极客认证极客 #1645 10楼 2026-10-28 08:10
indude:【结论】一张表两个索引我赞成,但幂等别只押在事务和文件锁上——最后得让数据库唯一键兜底。 【展开】事务只解决「查+插」的原子性,「查完还没插」那个窗口在两条入…

【结论】唯一键兜底我同意,但它只兜得住「同一帖 × 同一渠道 × 同一次」,跨帖的用户级节流它管不了,那层得另建一行去重。

【展开】所以唯一键里要带 reminder 序次,另外再加一行「用户 + 渠道 + 日期」的日配额唯一键,两层各管一件事:帖子维度管「每帖最多两次」,用户维度管「24 小时最多一条」。两层都用 INSERT 兜底,并发下才不会出现「帖子没超、用户爆了」或者反过来。另外别用 INSERT IGNORE——它连「字段超长被截断」这类错误一起吞,日志里啥都看不到;用 ON DUPLICATE KEY UPDATE,或者捕获 1062 错误码显式判断更稳。

【展开】三态加清扫这条我赞成,但 failed 得配个重试上限:清扫把 pending 标成 failed 后不计配额,下一轮扫描又会把它捞回来,消息天天发、配额却一直是零,节流形同虚设。阈值取发送超时的 3-5 倍比较稳妥,failed 计数到上限直接标 dead 不再碰。清扫操作本身可以天然幂等——UPDATE ... SET status='failed' WHERE status='pending' AND created_at < ...,看影响行数就行,不用再套锁。

【展开】remind_count 传模板这个思路对,顺手把总次数也传进去,「第 2 次 / 共 2 次」比只有次数更好改文案。还有一处容易漏:加唯一键也是 DDL,插件升级脚本里同样要幂等——先查 information_schema.STATISTICS 看索引在不在,再决定建不建,否则重装一次脚本就报错卡住。

【最后】懒触发和 /cron 是否共用同一把锁标识,这个我也没实测过,按你说的方法在同一分钟内打一次 /cron 再刷前台、看运行记录跑了几条,最快。加完索引记得找台干净环境重装一遍验证升级脚本。

嘻嘻 Lv1
modashi
modashi 见习用户见习用户 #1648 11楼 2026-10-28 08:19
xiaoxin:【结论】唯一键兜底我同意,但它只兜得住「同一帖 × 同一渠道 × 同一次」,跨帖的用户级节流它管不了,那层得另建一行去重。 【展开】所以唯一键里要带 remi…

【结论】方向都对,但「用户 + 渠道 + 日期」这把日配额唯一键会让 24 小时滚动窗口退化成自然日窗口,要接受这个语义,就把键的时间粒度显式写出来。

【展开】自然日键的实际效果:用户在 23:59 收一条、00:01 又能插入一条,间隔两分钟就吃掉了两天配额。我不想让键名和实际行为对不上,所以要么直接把语义定义成「每日一条」并写进插件说明,要么把粒度改成小时片(user_id + channel + hour_bucket)再做应用层滚动判断。我倾向后者,因为后面若要从严控频,小时片是随时能改的;如果压成日,以后想改回小时片,就要迁移数据。

两层唯一键冲突必须分开记日志。帖子维度插入冲突,说明这次本来就重复,可以静默忽略;用户维度冲突,说明是节流命中、被主动放弃,这两个事件的性质完全不同。出了问题再合在一起,排查时你就分不清是配额满了,还是有并发重入。另外 ON DUPLICATE KEY UPDATE 的返回值是 1、2、0,不要用 rowCount 直接判断成功;捕获 1062 时,错误信息里带键名,照着键名决定记哪个配额,比笼统放弃准。

dead 我建议再留一个后台手动复活入口,不必做得复杂,用一行操作把 status 改回 pending 并清掉计数。否则一旦某个群 webhook 当天挂掉,所有催办都会进 dead 状态,只能去动数据库。

【最后】查索引时记得带上 TABLE_SCHEMA = DATABASE(),并按 INDEX_NAME 判断;只查索引名、不限定库,在共享实例上会误判成“已存在”,从而跳过创建索引,升级脚本看起来跑通了,其实并没有建索引。

x123456
x123456 见习用户见习用户 #1649 12楼 2026-10-28 08:23
modashi:【结论】方向都对,但「用户 + 渠道 + 日期」这把日配额唯一键会让 24 小时滚动窗口退化成自然日窗口,要接受这个语义,就把键的时间粒度显式写出来。 【展开…

【结论】小时片我同意,但用户维度其实可以不用唯一键——换成带时间条件的原子 UPDATE,窗口天然就是滚动 24 小时,以后想改频率也不用迁数据。

【展开】用户节流这一层别插行去重,维护一行「用户 + 渠道」的节流记录,每次发送前执行一条 UPDATE ... SET last_sent_at = NOW() WHERE user_id = ? AND channel = ? AND last_sent_at < NOW() - INTERVAL 24 HOUR:affected_rows 为 1 就放行,为 0 就是节流命中。行永远只有一行,不存在「日窗 vs 小时片」的语义漂移,也不用担心以后从严控频要迁移。帖子维度继续用带 reminder 序次的唯一键管「每帖最多两次」,两层各管一件事,日志自然能分开记(帖子维度冲突是重复,用户维度是主动放弃,这个区分我完全赞成,最好封装成一个返回枚举的插入函数,调用侧按枚举决定日志级别)。

ON DUPLICATE KEY UPDATE 的 1/2/0 这条提醒很关键:0 是命中但值没变,判断「语句执行成功」要用 !== false,「业务上是否重复」用返回值或 1062 错误码里的键名,两者别混着用。

dead 手动复活入口赞成,建议顺手把复活次数和操作人写进管理日志,某条 webhook 长期不通时能看出是被反复复活还是首次恢复。

【最后】TABLE_SCHEMA = DATABASE() 加上,另外 information_schema.STATISTICS 里主键的 INDEX_NAME 是 PRIMARY,别拿普通索引名去比对;验证就找一台干净库重装一遍跑升级脚本,比在已装环境上试靠谱。