# 05 · 业务规则与状态机 > **读者**:实现领域逻辑的 AI(最易「看起来像但算错」) > **前置**:[03-data-model.md](03-data-model.md)、[04-api.md](04-api.md) > **源码**:[`service/`](../../services/)、[`model/models.go`](../../models/models.go) --- ## 1. 注册与引导 源:[`routers/web/auth.go`](../../routers/web/auth.go)、[`services/auth.go`](../../services/auth.go) | 规则 | 细节 | |------|------| | 管理员 | **仅** `/install` 向导创建(不再「首注册变管理员」) | | 开放注册 | 安装完成后开放;不依赖 SMTP | | 邮箱验证码 | `require_email_code = mailReady`;邮件未就绪时可无码注册 | | 会话 | Cookie `jiang13_session` = opaque id;表 `sessions`;HttpOnly + SameSite=Lax;HTTPS 时 Secure;TTL 7 天滑动续期 | | 吊销 | 登出删当前 session;禁言 / 重置密码删该用户全部 session | | HMAC 密钥 | `{DATA}/.jwt_secret` 仅 CSRF 等 HMAC(**不是**浏览器登录 JWT) | 密码:bcrypt;最小长度来自 `password_min_len`(默认 6)。 --- ## 2. 内容审核 ```mermaid stateDiagram-v2 [*] --> pending: 普通用户发帖或评论 [*] --> published: admin或verified免审 pending --> published: 管理员通过 pending --> rejected: 管理员拒绝 published --> pending: 非免审用户编辑后可再进审 ``` | 规则 | 细节 | |------|------| | 免审 | `role=admin` 或 `verified=true`(`SkipsModeration`) | | 可见性 | `pending`/`rejected`:**仅作者与管理员**可见(对外表现为 404) | | 列表 | 公开 Feed 只出 `published` | | 拒绝 | 可写原因;通知作者(站内信 kind=`reject`,可选邮件) | | 待审提醒 | 通知管理员(kind=`moderation`) | | 游客评论 | 通常直接或按实现进入审核;勿假设与登录用户完全相同 | 源:[`service/post.go`](../../services/post.go) `CanViewPost`、[`service/comment.go`](../../services/comment.go)。 --- ## 3. 编辑时限与锁 | 对象 | 规则 | |------|------| | 帖子 | 普通用户在 `post_edit_window_hours`(默认 24)内可编;超时不可(管理员除外) | | 帖子 | `edit_locked=true` 时非管理员不可编 | | 评论 | `comment_edit_window_minutes`(默认 3) | | 评论 | 帖子 `comments_locked` 时禁止新评论 | 详情接口返回 `can_edit`、`edit_block_reason`、`post_edit_window_hours`。 修订:每次成功修改前写入 `post_revisions` / `comment_revisions`(旧内容快照)。 --- ## 4. 经验 Exp(不可消费) | 事件 | Delta | |------|------| | 发帖成功(公开路径) | +10 | | 评论成功 | +2 | | 帖子被点赞 | +1(作者) | 源:[`service/post.go`](../../services/post.go)、[`service/comment.go`](../../services/comment.go)、[`service/badge.go`](../../services/badge.go) `AddExp`。 等级门槛见 [03-data-model.md](03-data-model.md) §4。管理员设 level 时应同步 Exp 到门槛值。 --- ## 5. 内容门控(红action) 源:[`service/content.go`](../../services/content.go)、[`handler/api.go`](../../routers/api/api.go) `APIPostDetail`、[`service/unlock.go`](../../services/unlock.go) ### 5.1 出口顺序(详情) 1. `SanitizePostHTML`(消毒) 2. 若 **游客**:`RedactMembersOnlyHTML` + `RedactReplyOnlyHTML` 3. 若 **已登录** 且非管理员、非作者、且未回复:仅 `RedactReplyOnlyHTML` 4. 作者与管理员:members/reply 块不遮 5. 积分块:按已解锁 key 集合 `RedactPointsOnlyHTML`;作者/管理员策略以实现为准(作者可免费解锁记录) 搜索 / SEO:`RedactGatedPostHTML` = members + reply + points 全遮。 ### 5.2 积分解锁 | 项 | 值 | |----|-----| | block_key | `hex(sha256(innerHTML))[:16]` | | cost | `data-cost`,最小 1 | | 读者 | 扣 `cost`(reason=`unlock_spend`) | | 作者分成 | `cost * 70 / 100`(`CreatorSharePercent`),reason=`creator_income`;并累加 `creator_income_total` | | 平台留存 | 剩余 30%(无单独流水,表现为读者扣全额、作者只加 70%) | | 作者自己 | cost=0 记解锁,无分成 | | 已解锁 | 返回错误「已解锁」 | | 防刷 | 双方账号注册未满 **7 天** 且 **LastLoginIP 相同** → 拒绝整单 | --- ## 6. 特殊帖类型 ### 6.1 问答 question - `question_resolved` 布尔;作者(或管理员)可切换 - 列表/详情用图标展示已解决状态 ### 6.2 投票 poll | 规则 | 细节 | |------|------| | 选项数 | 2–10;单选项 ≤64 字 | | 多选 | `multi`;`max_choices` 钳制在 1..选项数 | | 截止 | `ends_at` 可选;过期或 `closed` 不可再投 | | 投票 | 每用户每帖;已投不可改(`ErrPollAlreadyVoted`) | | 结束 | 作者或管理员 `poll/close` | ### 6.3 悬赏 bounty ```mermaid stateDiagram-v2 [*] --> open: 发帖托管积分 open --> awarded: 采纳他人已发布评论 open --> refunded: 退款 ``` | 规则 | 细节 | |------|------| | 发帖 | 积分 ≥1;立即 `bounty_escrow` 扣作者积分 | | 采纳 | 不能采纳自己的回复;评论须 published;全额给评论作者 `bounty_award` | | 退款 | 状态 open;作者在**无他人已发布回复**时可退;**管理员始终可强制退** | | 退款后 | status=`refunded`,`bounty_points=0`,积分退回作者 | ### 6.4 抽奖帖 lottery | 规则 | 细节 | |------|------| | 中奖人数 | 1–20 | | 参与者 | 已发布评论且 **非楼主**;按用户去重(保留最早评论) | | 开奖 | 作者/管理员;人数不足报错;随机抽取;写 `post_lottery_winners`;status=`drawn` | --- ## 7. 签到与每日抽奖 源:[`service/points.go`](../../services/points.go) ### 签到 - 自然日 `YYYY-MM-DD`(服务器本地时区)每用户一次 - 连续:若昨日报到则 streak+1,否则 1 - 奖励:`5 + (streak-1)`,封顶 **15**,保底 5 - 写 `check_ins` + `point_ledgers` reason=`check_in` ### 每日抽奖 - 每天一次;`cost=0` - 奖池权重:0×40, 2×30, 5×18, 10×10, 20×2 - 中奖积分入账 reason=`lottery` --- ## 8. 评论特殊规则 | 规则 | 细节 | |------|------| | 楼层 | 按帖递增 | | 私密评论 | 仅作者、帖作者、管理员、以及相关可见链可见(见 `canViewPrivate`) | | 嵌套 | `thread_parent_id` 在父不可见时回挂祖先 | | @提及 | 解析后发 kind=`mention` | | 回复提醒 | kind=`reply`;可选 SMTP | | HasUserReplied | 已发布或审核中的评论算「已回复」(不含被拒),用于 reply-only | --- ## 9. 举报处理 管理员 `handle` action: | action | 效果 | |--------|------| | dismiss | 驳回举报 | | resolve | 标记已处理(不必然删内容) | | reject_post | 拒绝/下架帖 | | reject_comment | 拒绝评论 | 结果通知举报人(kind=`report_result`)。 --- ## 10. 友链 | 规则 | 细节 | |------|------| | 申请 | 登录用户;可上传 logo | | 回链检测 | 设置开启时抓取 reciprocal 页检查是否含本站链接 | | 通过 | 可写入品牌 `site_friend_links`(视实现:首页展示链接) | | 展示开关 | nav / footer / aside 独立 | --- ## 11. 敏感词与限流 - 敏感词:`forum_settings.filter_words`(Admin SSR 可改并热更);旧文件可导入 - 限流动作键:post / comment / register / login / report / message / friend_link 等;窗口秒与次数来自 settings(Admin 可改基础四项+窗口) --- ## 12. 徽章自动授予 定期或触发时检查 `BadgeDef`(kind=auto):tenure_days / likes_received / creator_income 达阈值则写入 `user_badges`。限定徽章仅管理员发放。 --- ## 13. 置顶排序语义 | 标记 | 首页全部 Feed | 板块 Feed | |------|---------------|-----------| | `pinned` | 抬升 | 抬升 | | `board_pinned` | **不**抬升 | 抬升 | | `featured` | 标记展示,不一定改变排序 | 同左 | 具体 SQL/排序实现见 [`service/post.go`](../../services/post.go) ListItems。