Macro数据库规则CS-01到CS-38深度解读:资深Rust工程师的DB哲学
【免费下载链接】macroMacro is a unified workspace for teams: email, chat, docs, tasks, agents, calls, and CRM — @-linked together with shared AI memory.项目地址: https://gitcode.com/GitHub_Trending/macro3/macro
Macro是一个面向团队的统一工作区:邮件、聊天、文档、任务、AI Agent、通话与 CRM 全部通过 @ 引用串联,并共享一套 AI 记忆。支撑这套复杂系统的,是一套写进代码库的"军规"——本文带你逐条解读Macro 数据库规则 CS-01 到 CS-38,看懂资深 Rust 工程师藏在这些规则背后的 DB 哲学。🗄️
CS 规则是什么?一分钟看懂规则体系
这些规则全部定义在 docs/STYLE_GUIDE.md 中,是整个项目代码评审的"单一事实来源"。
每条规则只占一行,格式统一为:规则ID [作用域] 规则内容 (证据 · 强制手段 · 文档)。ID 前缀区分技术栈:
| 前缀 | 范围 |
|---|---|
CS-## | Rust 后端(crates/、services/、tooling/) |
FE-## | 前端与共享 TypeScript(apps/web、packages/) |
CS 规则按作用域分成 10 个标签:[db]数据库与迁移、[types]类型设计、[cfg]配置与环境、[err]错误与可观测性、[arch]架构边界、[api]API 设计、[sec]安全与权限、[rust]Rust 惯用法、[perf]性能、[test]测试。
💡规则 ID 永久稳定——评审时可以引用"见 CS-30",规则只增不删、永不重编号。删除会留空号,新规则用下一个空闲数字追加。这让规则库像法律条文一样可追溯。
CS-01~CS-09:数据库九条铁律(DB 哲学核心区)
这 9 条是全文最精华的部分,几乎每条都来自真实踩坑(括号中的 # 号即 PR 编号)。
CS-01 · ID 必须在应用层生成 UUIDv7永远不要用数据库的gen_random_uuid()(那是不可排序的 UUIDv4)。UUIDv7 天然按创建时间排序,主键扫描即时间线。在迁移文件 20260831172113_user_api_key_id_name_hash.sql 中就能看到注释直接引用 "CS-01",把规则钉在代码旁边。
CS-02 · 一切可能竞争的插入都要幂等种子数据、回填脚本一律带ON CONFLICT处理——重跑一万次,数据库状态不变。
CS-03 · 优先自然键/复合键如果一张表本来就按业务列查询排序,就别再造一个代理 ID。REST 路由也直接用自然 ID。
CS-04 · 用户列统一叫user_id拒绝owner_user_id、author_id这类"创造性命名",跟随既有表的约定。
CS-05 · 级联删除必须有"剧本"新表上线前就要想清楚:删除 A 时,挂在它下面的 B、C 怎么办?不许把这件事留给数据库默认行为。
CS-06 · 拒绝冗余索引主键前缀已经覆盖的列,不需要再单独建索引——多出来的索引只会拖慢写入。
CS-07 · 别存上下文里已有的列租户级已固定的 scoping id 再存一份,就是纯粹的垃圾数据。
CS-08 · 默认使用编译期校验查询sqlx::query!/query_as!是默认选项,SQL 写错直接编译失败;裸query只留给真正无法静态化的动态查询。配套工作流详见 docs/DATABASE_DEVELOPMENT.md。
CS-09 ·.sqlx缓存只在仓库根目录统一用nix develop --command just prepare_db刷新,绝不允许单个 crate 私藏一份缓存——缓存漂移是团队协作的头号杀手。
CS-10~CS-13:类型设计哲学
- CS-10:ID 和 Token 一律 newtype 包装,构造时校验格式,杜绝"到处飞的裸 String"。
- CS-11:封闭字符串集合就是枚举,不是 String。
- CS-12:可空就用
Option<T>,不许用哨兵值表达"没有"。 - CS-13:三态数据(未加载 / 缺失 / 有值)用一个扁平枚举表达,而不是层层嵌套的 Option。
CS-14~CS-18:配置与环境的"快速失败"
CS-14规定所有环境变量必须走macro_env_var/macro_config共享 crate,禁止手写std::env::var——配置入口唯一化,clippy 直接封禁裸调用。CS-15要求配置在服务启动时就校验完:缺环境变量应该杀死进程,而不是杀死某个请求。这两条合起来就是"快速失败"哲学的落地。CS-16~CS-18 则细化到错误上下文、Doppler 密钥命名一致性等运维细节。
CS-19~CS-22:错误与可观测性
CS-19:第三方错误必须有自己的错误变体,别把 JWT 解析失败塌缩成"内部错误"——排障时你需要的正是那个具体来源。CS-20要求依赖限流的外部服务商时必须备好后路(降级模型、重试或文档化的降级路径)。CS-21强调用量计量要覆盖每一条调用路径,包括 MCP 触发的工具调用。CS-22规范 tracing 埋点:Result函数必须带err字段,错误用结构化字段记录。
CS-23~CS-29:架构边界——控制"巨石"生长
这组规则直接回应"代码库如何不腐化":
- CS-23:禁止继续膨胀
macro_db_client——新领域逻辑必须开新 crate,通吃型 crate 只能收缩。 - CS-24:单文件超过约 1000 行就拆分,别等评审员开口。
- CS-25:
mod.rs只声明子模块,不承载逻辑。 - CS-26:先复用再重写——大概率已存在的逻辑(服务客户端、权限检查、OAuth 工具)必须找到并复用。
- CS-27:共享领域表只能由属主 crate 读写,其他地方禁止裸 SQL。
- CS-28:别急着把一次性代码抽成共享 crate,依赖方向必须指向"通用"。
- CS-29:泛滥的根目录文件(如 Dockerfile)归入专门目录。
CS-30~CS-35:API 与处理层设计
CS-30要求 Axum handler 通过State注入共享服务而非Extension(ast-grep 规则自动拦截违规写法)。CS-31强调横切服务挂到属主领域服务上,而不是随手挂在路由层。CS-32~CS-35则约束模型一致性:新增 API 模型必须镜像既有模型的形状、兄弟端点共用同一 DTO 并一起迁移、泛型抽象要设计成T → U而不是T → T。
CS-36~CS-38:安全与权限——最小权限三连
- CS-36:权限授予必须是无状态 HTTP 端点,而不是内存信道消息——因为断线重连后内存流就丢了。
- CS-37:向下游传递数据时,签发窄作用域 Token,而不是转发用户完整 JWT。最小权限靠结构实现,而非靠自觉。
- CS-38:工具(Tool)响应必须是消息链的合法成员,携带
tool_call_id与链元数据——在多 Agent 场景下,消息链完整性就是安全边界。
如何落地:just check单一门禁
规则不是挂在墙上的标语,而是可执行的质量门:在项目根目录运行just check,会对你的变更执行 格式化 + lint + 代码规则检查,每条发现都以文件:行号 [规则ID]输出,并附上修复命令。just check full额外加上 tsc 与 clippy。
配合 docs/DATABASE_DEVELOPMENT.md 中的数据库开发流程(迁移必须用 SQLx 生成、迁移先于服务部署、删列走"两阶段"),这套 CS 规则构成了一个闭环:规则 → 自动检查 → 评审引用 → 持续沉淀新规则。
总结:DB 哲学三句话
- 数据库是共享契约——迁移必须兼容已部署代码,幂等优先,级联要有剧本(CS-01~CS-09)。
- 类型系统是最好的防御——把非法状态变成编译错误,而不是运行时事故(CS-08、CS-10~CS-13)。
- 架构靠规则防腐——属主制、快速失败、最小权限,让十年后的代码库依然可读(CS-15、CS-23、CS-37)。
这套规则的价值不只属于数据库工程师:任何参与 Macro 贡献的开发者,都能从中学到"如何写出让别人放心的代码"。🚀
【免费下载链接】macroMacro is a unified workspace for teams: email, chat, docs, tasks, agents, calls, and CRM — @-linked together with shared AI memory.项目地址: https://gitcode.com/GitHub_Trending/macro3/macro
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考