RaisFastRaisFast
Content Types

Schema 管理

CLI 命令、Admin API、热重载和数据库迁移策略。

通过 CLI、Admin API 或直接编辑 TOML 文件来管理内容类型 Schema。变更无需重启服务器即可生效。

CLI 命令

创建内容类型

raisfast ct new course

extensions/content_types/course.toml 生成基础 TOML 脚手架文件。

校验 Schema

raisfast ct check

校验内容类型目录中的所有 TOML 文件。报告以下错误:

  • 缺少必填字段(namesingularpluraltable
  • 无效的字段类型
  • 重复的表名或保留表名
  • 循环关联引用

生成 TypeScript 类型

raisfast ct types course -o types/course.ts

从内容类型定义生成 TypeScript 接口,包括字段类型、可选标记和关联类型。

Admin API

通过 Admin API 在运行时管理 Schema:

GET    /api/v1/admin/content-types              列出所有 Schema
GET    /api/v1/admin/content-types/{singular}   获取单个 Schema
POST   /api/v1/admin/content-types              创建 Schema
PUT    /api/v1/admin/content-types/{singular}   更新 Schema
DELETE /api/v1/admin/content-types/{singular}   删除 Schema

创建 Schema

curl -X POST http://localhost:9898/api/v1/admin/content-types \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Project",
    "singular": "project",
    "plural": "projects",
    "table": "projects",
    "fields": [
      {"name": "title", "field_type": "text", "required": true},
      {"name": "status", "field_type": "enum", "enum_values": ["active", "completed"], "default": "active"}
    ],
    "protocols": ["timestampable", "ownable"]
  }'

这一步请求完成四件事:

  1. 校验 Schema
  2. 写入 TOML 文件到 extensions/content_types/
  3. 迁移 数据库(创建 projects 表)
  4. 注册 路由到内存

更新 Schema

curl -X PUT http://localhost:9898/api/v1/admin/content-types/project \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": [
      {"name": "title", "field_type": "text", "required": true},
      {"name": "status", "field_type": "enum", "enum_values": ["active", "completed", "archived"], "default": "active"},
      {"name": "priority", "field_type": "integer", "min": 1, "max": 5}
    ]
  }'

这会:

  1. 更新 TOML 文件
  2. 迁移 数据库(通过 ALTER TABLE 添加新的 priority 列)
  3. 重新注册 Schema 到内存

删除 Schema

curl -X DELETE http://localhost:9898/api/v1/admin/content-types/project \
  -H "Authorization: Bearer TOKEN"

这会注销路由并删除 TOML 文件。数据库表会被保留 — 不会丢失数据。

热重载

内容类型 Schema 使用无锁 ArcSwap 加载到内存中,实现零停机热重载:

  • TOML 文件变更 在下次请求时生效(使用文件监控时)
  • Admin API 变更 立即生效
  • 动态路由/api/v1/cms/{*path})处理启动后添加的内容类型

迁移策略

系统采用安全的增量迁移方式:

新内容类型

CREATE TABLE IF NOT EXISTS {table} (
  id TEXT PRIMARY KEY,
  {field_columns},
  {protocol_columns}
)

新增字段

当 Schema 增加新字段时,系统比较期望列与实际列,生成:

ALTER TABLE {table} ADD COLUMN {column} {type}

只有增量变更会自动执行。

类型变更

如果字段类型发生变化(如 textinteger),系统检测到不匹配后会生成重建迁移脚本,保存到 migrations/manual/

  • SQLite:使用 PRAGMA foreign_keys=OFF,创建新表、复制数据、删除旧表、重命名
  • PostgreSQL:用事务包裹 BEGIN / COMMIT
  • MySQL:使用 SET FOREIGN_KEY_CHECKS=0

这些脚本需要手动审核和执行。

绝不会发生的事

  • 列不会被删除 — 从 TOML 中移除字段不会删除列
  • 数据不会被修改 — 现有值保持不变
  • 表不会被删除 — 删除 Schema 会保留表

索引

自动为以下情况创建唯一索引:

  • 标记为 unique = true 的字段
  • 显式定义的 [[indexes]]
[[indexes]]
fields = ["slug"]
unique = true

[[indexes]]
fields = ["status", "created_at"]

中间表

对于 many_to_manymany_way 关联,中间表会自动创建:

CREATE TABLE IF NOT EXISTS {source}_{target} (
  {source_singular}_id TEXT NOT NULL,
  {target}_id TEXT NOT NULL,
  PRIMARY KEY ({source_singular}_id, {target}_id)
)

受保护的表

系统内置表不能作为内容类型的表名,包括:userspostspagescategoriestagsmediacommentsproductsorderswallets 等所有内置表。

保留路由段(authadminusersmedia 等)不能用作 singularplural 名称。

文件结构

extensions/
  content_types/
    course.toml          # 课程内容类型
    instructor.toml      # 讲师内容类型
    lesson.toml          # 课时内容类型
migrations/
  manual/                # 类型变更重建脚本(需手动审核)

On this page