数据库设计
Clara 52 张核心表结构、关键字段与关系,插件自建表的命名与规范参考。
05 · 数据库设计
DDL 源码:[install/schema.php](../install/schema.php)(`clara_schema()` 返回 DDL 数组,`{P}` 为表前缀占位符,安装时替换为实际前缀如 `clara_`)。引擎统一 InnoDB + utf8mb4\_unicode\_ci。
新装站点由安装向导执行全量 DDL;存量站点升级走后台「系统工具 → 数据库升级」(对比 schema 声明增量执行)。
1. 表清单总览(52 张核心表 · install/schema.php 建表,另有 cron_runs 等升级增量表)
| 领域 | 表 | 用途 |
|---|---|---|
| 系统 | `settings` | KV 配置(站点设置 / 插件启用列表 / 插件配置) |
| 用户 | `users` | 用户主表(账号/头像/组/经验/签到统计/隐私/记住我 token) |
| 用户 | `user_groups` | 用户组(perms JSON / is\_admin / min\_exp 门槛 / auto\_upgrade) |
| 用户 | `user_group_maps` | 用户 ↔ 附加组多对多映射 |
| 用户 | `follows` | 关注关系(uk user+target) |
| 内容 | `forums` | 版块(parent\_id 树 / type 1分类2版块 / perms JSON 覆盖 / moderators 逗号uid / 统计冗余) |
| 内容 | `forum_categories` | 版块子分类(版块内话题分类:forum\_id + name + sort;发帖可选、版块页 ?cat= 筛选、后台版块编辑页增删改) |
| 内容 | `threads` | 主题(计数冗余 / is\_top 置顶 / is\_essence 精华 / is\_closed / status 软删 / category\_id 子分类 / tags 逗号分隔 / last\_post\_at 排序键 / bounty\_amount+bounty\_cid 悬赏托管 / best\_post\_id 最佳答案) |
| 内容 | `posts` | 回帖(reply\_post\_id 楼中楼引用链 / is\_anonymous 匿名 / status 软删) |
| 内容 | `topics` | 专题聚合(专辑/合集:forum_id/name/description/cover/auto_tag/auto_kw/status/sort/thread_count 冗余,聚合详情页与总览页展示) |
| 内容 | `topic_threads` | 专题 ↔ 主题关联(uk topic+thread 幂等;sort 排序) |
| 内容 | `attachments` | 附件(type=文件/网盘链接 / driver/path/url 云存储位置 / code 网盘提取码 / thread\_id+post\_id 关联 / price+currency\_id 出售 / perm\_type+perm\_groups 下载权限 / downloads 统计) |
| 内容 | `attachment_purchases` | 附件购买记录(uk attachment+user 幂等;price/currency\_id 成交快照) |
| 互动 | `polls` | 投票主表(uk thread / max\_choices 最多可选 / expires\_at 截止 / voters 参与人数) |
| 互动 | `poll_options` | 投票选项(poll\_id / text / votes 票数 / sort) |
| 互动 | `poll_votes` | 投票记录(uk poll+option+user 防重投) |
| 互动 | `likes` | 点赞(uk user+target+target\_id,target 区分主题/回帖) |
| 互动 | `favorites` | 收藏(uk user+thread) |
| 财务 | `currencies` | 货币定义(code/name/sign/is\_default) |
| 财务 | `user_currency` | 用户余额(uk user+currency) |
| 财务 | `currency_logs` | 货币流水(amount/after 快照/type/note) |
| 财务 | `credit_rules` | 积分规则(event 事件 / currency\_id / amount 正奖负扣 / daily\_limit 每日上限 0 不限 / enabled) |
| 财务 | `credit_logs` | 积分发放记录(uk event+operator+source+user 去重防刷 / log\_date 每日上限计数;惩罚扣减失败自动回滚占位) |
| 成长 | `exp_logs` | 经验流水(amount/after/type) |
| 签到 | `checkins` | 签到记录(uk user+check\_date;rewards JSON,补签标记 `{"repair":1}`) |
| 商城 | `memberships` | 会员套餐(price/duration\_days/checkin\_mult 签到倍率/name\_color) |
| 商城 | `user_memberships` | 用户会员记录(start\_at/end\_at,多套餐叠加取最晚) |
| 商城 | `avatar_frames` | 头像框(effect 特效 20 种/color/color2 双色/price/duration\_days/membership\_id 专属) |
| 商城 | `user_frames` | 用户头像框(uk user+frame,expire\_at 过期) |
| 荣誉 | `medals` | 勋章(type 1手动2自动;cond\_type/cond\_value 自动条件) |
| 荣誉 | `user_medals` | 用户勋章(uk user+medal 幂等;is\_wear 佩戴) |
| 社交 | `gifts` | 礼物定义 |
| 社交 | `gift_logs` | 赠送记录(from/to/thread/message) |
| 运营 | `card_batches` / `cards` | 卡密批次与卡密(status/bind\_uid 绑定/expire\_at) |
| 运营 | `invitation_codes` | 邀请码(creator/used\_by/expire\_at) |
| 运营 | `announcements` | 公告(type/start\_at/end\_at 定时) |
| 通知 | `notifications` | 站内通知(is\_read;notify() 合并同目标未读) |
| 邮件 | `mail_logs` | SMTP 发送日志(status/error) |
| 系统 | `login_logs` | 登录审计日志(login\_name 尝试账号/user\_id 匹配用户/ip/user\_agent/success/reason 失败原因;Cron 按保留天数自动清理) |
| 系统 | `search_logs` | 搜索日志(keyword 去重 + hits 计数 + last_at,全文搜索热词统计) |
| 系统 | `cron_runs` | 计划任务运行记录(name/ok/summary/ran\_at;每任务保留最新一条 + 30 天历史;v2026.09.06 经数据库升级建表) |
| 财务 | `transfer_logs` | 用户转账流水(from\_uid/to\_uid/currency\_id/amount/fee,transfer\_execute 事务内写入) |
| 内容 | `thread_purchases` | 付费主题购买记录(uk thread+user 幂等;成交价快照) |
| 互动 | `forum_follows` | 版块关注(uk user+forum;版块页关注者列表与通知) |
| 私信 | `pm_conversations` / `pm_messages` | 私信会话(双方独立删除标记)与消息正文;权限形态 `perm_enabled('pm')` |
| 运营 | `reports` | 举报(type/target\_id/reporter\_id/reason/status/handler\_id,后台队列处理) |
| 系统 | `admin_logs` | 后台操作日志(module/action/target/detail/operator\_id,AdminLogsController 展示) |
| 系统 | `ip_bans` | IP 封禁(ip/reason/expires\_at;ip\_ban\_guard() 请求期拦截) |
| 系统 | `audit_logs` | 发帖审核日志(AdminAuditController 过审/拒绝留痕) |
| 系统 | `online` | 在线用户(uid/session\_id/ip/last\_at;60s 限流清理,online\_users() 统计) |
| GEO | `geo_bot_stats` | AI 爬虫访问监控(bot/day/hits/last\_at/sample\_url/geo\_endpoints 命中端点;GeoService::recordBotHit 写入,列由数据库升级补建) |
插件自建表(前缀 `plugin_{目录名}_`):
| 表 | 所属插件 | 用途 |
|---|---|---|
| `plugin_ai_reply_providers` | ai\_reply | AI 提供商列表(base\_url/key/model/启用/失败熔断计数) |
| `plugin_ai_reply_logs` | ai\_reply | 调用日志(触发源/请求/回答/状态/耗时,后台日志面板与 retry 用) |
| `plugin_ai_writer_titles` | ai\_writer | 标题池(forum\_id/category\_id/title/status 状态机 pending→preview/published/failed/content\_preview 暂存正文/thread\_id 已发布关联/retry\_count/tags\_preset 预设标签) |
| `plugin_ai_writer_tasks` | ai\_writer | 发布任务(forum\_id/category\_id/bot\_uid 机器人/interval\_sec≥300 或 daily\_time/freq\_type/model/temperature/max\_tokens/prompt 任务级覆盖/batch\_count/next\_run\_at/enabled) |
| `plugin_ai_writer_jobs` | ai\_writer | 异步生成任务(type=title/article/preview、topic、count\_target 目标数/inserted 实际入库/skipped/status pending→running→done/fail、token 轮询凭证、fail\_streak) |
| `plugin_ai_writer_logs` | ai\_writer | 生成日志(action=title/article/publish、Token 出入/耗时/触发源 lazy·cron·manual·preview、error) |
| `plugin_api_hub_log` | api\_hub | API 工具箱解析记录(user/service/input\_url/title/result\_url/cover\_url/cost\_cid/cost\_num/created\_at) |
| `plugin_rank_scores` | rank | (已废弃:site_rank v1.x 起改纯查询聚合,无自建表,卸载零残留——见 06 § 4.2) |
| `plugin_thread_visitors` | thread\_visitors | 帖子访客记录(thread\_id/user\_id/visited\_at,定期清理) |
| `plugin_member_wall` | member_wall | 会员墙上墙记录(付费上墙,购买走行锁 + 事务范例) |
| `plugin_ad_slots` / `plugin_ad_orders` | ad_self | 广告位定义与投放订单(坑位容量制;按天/周/月/年计费,懒过期 + 事务内行锁复查防超卖) |
| `plugin_lottery_threads` / `participants` / `slots` / `draws` / `winners` | lottery | 回帖抽奖 / 概率抽奖 / 转盘抽奖五表(服务端权威判定 + 扇区签名) |
| `plugin_ks_categories` / `questions` / `attempts` / `answers` / `users` / `logs` | ks_exam | 入站考试六表(题库分类/题目/组卷/作答/通过用户/日志) |
| `plugin_geo_qa_factory_queue` | geo_qa_factory | GEO 问答草稿队列(AI 生成 → 人工审核 → 一键发布并采纳) |
2. 核心表结构详解
users(用户主表)
id, username(uk), nickname, email(uk), password, -- 账号
avatar, avatar_frame, -- 头像 + 佩戴头像框
group_id(idx), -- 主组
email_verified, status, -- status>=0 可登录,-1 封禁
signature, bio, gender, homepage, location, -- 资料
thread_count, post_count, -- 冗余计数
exp, -- 经验值
checkin_days, checkin_total, checkin_last_date, -- 签到统计
remember_token, -- 记住我(64 hex)
invite_by, last_login_at, last_ip, created_at,
privacy_no_follow, privacy_no_reply, privacy_hide_social, -- 隐私开关
pwd_code, pwd_code_expires, -- 找回密码验证码
login_fails, locked_until -- 登录安全闭环(连续失败计数 / 临时锁定到期)
user\_groups(用户组 — 权限与等级合一)
id, name, color, -- 组名与徽章色
perms TEXT, -- 权限 JSON {"view":1,"thread":1,...}(16 键,含 attach/poll/bounty/anon_reply 内容形态键)
is_system, is_admin, -- 系统组 / 管理员组(全权限)
min_exp, auto_upgrade, -- 经验门槛 / 是否参与经验自动升级(等级组)
sort
等级组 = `auto_upgrade=1 AND is_admin=0`,经 `exp_level_groups()` 按 min\_exp 升序读取;管理员/版主等特殊组不参与自动升降级,前端也不显示经验进度。
forums(版块)
id, parent_id(idx), -- type=1 分类(容器)、type=2 版块(发帖)
type, name, description, icon, sort,
thread_count, post_count, last_thread_id, last_post_at, -- 冗余统计
perms TEXT, -- 版块级组权限覆盖 JSON {"{gid}":{"view":1,"reply":0}}
moderators VARCHAR(255), -- 版主 uid 逗号分隔
status, -- 0 关闭(仅管理员可见)
seo_keywords, seo_description, created_at
threads / posts(内容)
threads: forum_id(idx), user_id(idx), title, content(MEDIUMTEXT),
views, replies, likes, favorites, gifts, -- 计数冗余
is_top, is_essence, is_closed, status, -- status=1 正常 / 0 隐藏(回收站)
deleted_at, -- 前台软删时间戳(回收站保留计时;NULL = 后台隐藏,不自动清理)
tags VARCHAR(150), -- 半角逗号分隔(FIND_IN_SET 查询)
created_at, updated_at, edited_at,
last_post_at(idx 组合), last_post_user_id -- 列表排序与「最后回复」展示
posts: thread_id(idx), user_id(idx), reply_post_id, -- 楼中楼:指向被回复的 post id
content(MEDIUMTEXT), likes, status, created_at
checkins(签到)
user_id, check_date(DATE, uk 组合), days, -- 当日连签天数快照
rewards VARCHAR(500), -- 奖励 JSON;补签记录为 '{"repair":1}'
created_at
credit\_rules / credit\_logs(积分规则引擎)
credit_rules: id, event VARCHAR(40), -- thread_create / post_create / be_liked /
-- be_post_liked / be_favorited / thread_delete / post_delete
currency_id, amount DECIMAL, -- 正数奖励 / 负数扣除
daily_limit INT(0 不限), enabled, created_at
credit_logs: id, user_id, event, currency_id, amount,
operator_uid, -- 触发人(他人触发类事件;自赞不发放)
source_id, -- 主题/回复 id(与 operator_uid 组成去重键)
log_date DATE, -- 每日上限计数键
created_at
UNIQUE(event, operator_uid, source_id, user_id) -- 去重:点赞反复切换只发一次
发放链路:`CreditRuleService::apply()` → INSERT IGNORE 占位 → `currency_change(type='credit_rule')` 入账 → 失败(惩罚余额不足)回滚占位;规则长缓存 `Cache('credit_rules')`,后台变更主动失效。
3. 实体关系(ER 摘要)
user_groups 1──n users(group_id 主组) user_group_maps n──n(附加组)
users 1──n threads / posts(user_id)
forums 1──n threads(forum_id);forums 自关联(parent_id 分类树)
threads 1──n posts(thread_id);posts 自关联(reply_post_id 楼中楼链)
users n──n threads(likes: user+target+target_id / favorites: user+thread)
users 1──n user_currency / currency_logs(经 currencies 关联)
users 1──n user_memberships n──1 memberships(叠加,取 end_at 最晚)
users 1──n user_frames n──1 avatar_frames(uk user+frame)
users 1──n user_medals n──1 medals(uk user+medal 幂等)
users n──n follows(user_id → target_id)
users 1──n notifications / checkins / exp_logs
4. 数据一致性约定
- 冗余计数:threads.replies、forums.thread\_count/post\_count、users.thread\_count/post\_count 均为冗余字段,随发帖/回帖/删除同步增减;漂移时用后台「系统工具 → 重算统计」对账。
- 软删除:threads/posts 用 status=-1;列表查询统一走 `thread_visibility_sql()`(管理员见全部,普通用户只见 status=1)。
- 唯一键幂等:签到(user+date)、勋章(user+medal)、头像框(user+frame)、点赞(user+target+target\_id)均靠唯一键防重。
- 流水快照:currency\_logs/exp\_logs 记录变动后余额(after 列),便于审计与防刷统计(当日计数查询)。
- JSON 字段:user\_groups.perms、forums.perms、checkins.rewards 为 JSON 文本;写入方负责 `json_decode` 容错(`?: array()` 兜底)。
5. settings 表关键键位
| 键 | 内容 |
|---|---|
| `site_name` / `site_desc` / `site_url` / `brand_letter` / `site_favicon` | 站点基础信息 |
| `reg_email_verify` / `invite_enabled` | 注册策略 |
| `admin_login_email_verify` | 后台登录 2FA 开关 |
| `thread_edit_enabled` / `thread_edit_window` / `membership_edit` | 帖子编辑策略 |
| `exp_enabled` / `exp_thread` / `exp_post` / `exp_checkin` / `exp_daily_*` | 经验体系 |
| `checkin_reward` 相关 / `checkin_repair_enabled` / `checkin_repair_cost` / `checkin_repair_monthly` | 签到与补签 |
| `forum_layout` / `forum_layout_user_switch` | 版块列表布局(list/side + 访客切换) |
| `storage_driver` / `qiniu_*` / `oss_*` / `cos_*` | 云存储 |
| `smtp_*` | 邮件 |
| `upload_max_size` / `upload_exts` | 上传限制 |
| `attach_enabled` / `attach_max_size` / `attach_exts` | 通用附件(开关/大小/白名单) |
| `allow_anonymous_reply` | 匿名回复开关 |
| `enabled_plugins` / `installed_plugins` / `plugin_config_{dir}` | 插件状态与配置 |
| `group_guest` | 游客组 id |
| `trusted_link_hosts` | 友链信任域名白名单 |
| `notify_sound_enabled` / `notify_sound` | 通知提示音 |
| `cron_key` | 计划任务外部触发密钥(/cron.html?key= 校验;后台系统工具可重新生成) |
| `trusted_proxies` | 可信代理清单(XFF 采信白名单:空 = 默认 127.0.0.1,::1;none = 全不信任;支持 CIDR 如 172.16.0.0/12) |
| `currency_reconcile_last` | 货币对账最近报告 JSON(ran_at/accounts/mismatch/negatives,每日 Cron 与手动对账写入,后台「业务对账」卡片展示) |
本文档随系统发布维护;如发现与当前版本不符,欢迎到社区反馈。







