Content Types
协议
11 种可组合行为,无需代码即可为内容类型自动添加列和逻辑。
协议是可组合的行为模块。将它们添加到内容类型中,系统自动注入数据库列、验证规则和 API 逻辑 — 无需写代码。
快速示例
[content_type.implements]
protocols = ["timestampable", "ownable", "soft_deletable", "sortable"]
[[content_type.implements.protocols]]
name = "statusable"
values = "draft,published,archived"
default = "draft"全部 11 种协议
timestampable
自动管理 created_at 和 updated_at 时间戳。
| 列 | 类型 | 行为 |
|---|---|---|
created_at | TEXT | 创建时设置 |
updated_at | TEXT | 创建时设置,每次更新时刷新 |
protocols = ["timestampable"]ownable
自动追踪创建者和最后修改者。
| 列 | 类型 | 行为 |
|---|---|---|
created_by | INTEGER | 创建时从认证用户获取 |
updated_by | INTEGER | 每次更新时从认证用户获取 |
protocols = ["ownable"]soft_deletable
逻辑删除 — 记录被标记为删除而非真正移除。列表查询自动过滤 deleted_at IS NULL。
| 列 | 类型 | 行为 |
|---|---|---|
deleted_at | TEXT | 删除时设为当前时间戳 |
deleted_by | INTEGER | 删除时从认证用户获取 |
protocols = ["soft_deletable"]versionable
版本追踪,支持快照和恢复 API。
| 列 | 类型 | 行为 |
|---|---|---|
version | INTEGER | 每次更新递增(初始为 1) |
自动注册版本管理端点:
GET /admin/cms/{plural}/{id}/revisions 列出版本
GET /admin/cms/{plural}/{id}/revisions/{revision_id} 获取版本
POST /admin/cms/{plural}/{id}/revisions/{revision_id}/restore 恢复版本
GET /admin/cms/{plural}/{id}/revisions/{rev_a}/diff/{rev_b} 对比两个版本每次更新前,当前记录会自动快照到 content_revisions 表。删除记录时,所有版本自动清理。
protocols = ["versionable"]lockable
乐观锁 — 防止并发写入冲突。
| 列 | 类型 | 行为 |
|---|---|---|
lock_version | INTEGER | 初始为 1,每次更新递增 |
更新时检查 WHERE lock_version = {expected}。如果不匹配(被其他客户端修改),返回 409 Conflict。
protocols = ["lockable"]sortable
通过排序键实现默认排序。
| 列 | 类型 | 行为 |
|---|---|---|
sort_key | INTEGER | 默认 0,用于排序 |
默认排序:sort_key ASC。
protocols = ["sortable"]可配置 — 更改排序字段和方向:
[[content_type.implements.protocols]]
name = "sortable"
field = "priority"
direction = "desc"statusable
带允许值的状态机。
| 列 | 类型 | 行为 |
|---|---|---|
status | VARCHAR | 根据允许值验证 |
字符串模式(默认):
[[content_type.implements.protocols]]
name = "statusable"
values = "draft,published,archived"
default = "draft"数值模式 — 将标签映射为数据库中的数字:
[[content_type.implements.protocols]]
name = "statusable"
values = "pending=1,paid=10,shipped=20,completed=30"
default = "1"
mode = "numeric"数值模式下,API 接受标签("paid"),但存储数字(10)。
expirable
自动过滤过期记录。
| 列 | 类型 | 行为 |
|---|---|---|
expires_at | TEXT | 列表查询自动过滤 expires_at IS NULL OR expires_at > now |
protocols = ["expirable"]nestable
父子树结构。
| 列 | 类型 | 行为 |
|---|---|---|
parent_id | INTEGER | 父记录引用 |
depth | INTEGER | 树深度(0 = 根) |
position | INTEGER | 同级排序 |
protocols = ["nestable"]tenantable
多租户隔离。
| 列 | 类型 | 行为 |
|---|---|---|
tenant_id | VARCHAR | 按当前租户自动过滤(默认 "default") |
所有查询自动添加 WHERE tenant_id = ?,基于认证上下文。
protocols = ["tenantable"]metaable
任意 JSON 元数据。
| 列 | 类型 | 行为 |
|---|---|---|
__meta | JSON | 默认 {},可通过 __meta.{path} 查询参数过滤 |
protocols = ["metaable"]查询时过滤:
curl "http://localhost:9898/api/v1/cms/courses?__meta.featured=true"协议一览
| 协议 | 添加列 | 核心行为 |
|---|---|---|
timestampable | created_at, updated_at | 自动时间戳 |
ownable | created_by, updated_by | 自动追踪用户 |
soft_deletable | deleted_at, deleted_by | 逻辑删除 |
versionable | version | 快照 + 恢复 + 对比 API |
lockable | lock_version | 乐观锁(冲突返回 409) |
sortable | sort_key | 默认排序 |
statusable | status | 状态机 |
expirable | expires_at | 自动过滤过期 |
nestable | parent_id, depth, position | 树形结构 |
tenantable | tenant_id | 多租户隔离 |
metaable | __meta | JSON 元数据 |
组合协议
协议可以自由组合。一个典型的博客文章:
[content_type.implements]
protocols = ["timestampable", "ownable", "soft_deletable", "versionable", "sortable"]
[[content_type.implements.protocols]]
name = "statusable"
values = "draft,published,archived"
default = "draft"6 行 TOML 即可获得:自动时间戳、作者追踪、安全删除、版本历史、默认排序和状态机。
执行顺序
协议按优先级顺序执行(数字越小越先执行):
| 优先级 | 协议 |
|---|---|
| -600 | tenantable |
| -500 | ownable |
| -400 | timestampable |
| -300 | soft_deletable |
| -200 | expirable, nestable |
| -150 | statusable |
| -100 | lockable, sortable |
| 500 | versionable |
| 1000 | metaable |
这确保了租户隔离最先执行,版本快照最后执行。
