Schema Management
CLI commands, Admin API, hot-reload, and database migration strategy.
Manage content type schemas via the CLI, Admin API, or by editing TOML files directly. Changes take effect without restarting the server.
CLI Commands
Create a Content Type
raisfast ct new courseGenerates a scaffold TOML file at extensions/content_types/course.toml with the basic structure.
Validate Schemas
raisfast ct checkValidates all TOML files in the content types directory. Reports errors for:
- Missing required fields (
name,singular,plural,table) - Invalid field types
- Duplicate table names or reserved names
- Circular relation references
Generate TypeScript Types
raisfast ct types course -o types/course.tsGenerates TypeScript interfaces from a content type definition, including field types, optional markers, and relation types.
Admin API
Manage schemas at runtime via the Admin API:
GET /api/v1/admin/content-types List all schemas
GET /api/v1/admin/content-types/{singular} Get a single schema
POST /api/v1/admin/content-types Create schema
PUT /api/v1/admin/content-types/{singular} Update schema
DELETE /api/v1/admin/content-types/{singular} Delete schemaCreate a 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"]
}'This single request:
- Validates the schema
- Writes the TOML file to
extensions/content_types/ - Migrates the database (creates the
projectstable) - Registers the routes in memory
Update a 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}
]
}'This:
- Updates the TOML file
- Migrates the database (adds the new
prioritycolumn viaALTER TABLE) - Re-registers the schema in memory
Delete a Schema
curl -X DELETE http://localhost:9898/api/v1/admin/content-types/project \
-H "Authorization: Bearer TOKEN"This unregisters the routes and removes the TOML file. The database table is preserved — no data loss.
Hot-Reload
Content type schemas are loaded into memory using lock-free ArcSwap, enabling hot-reload without downtime:
- TOML file changes are picked up on the next request (when using the file watcher)
- Admin API changes take effect immediately
- Dynamic routes (
/api/v1/cms/{*path}) handle content types added after startup
Migration Strategy
The system uses a safe, additive migration approach:
New Content Type
CREATE TABLE IF NOT EXISTS {table} (
id TEXT PRIMARY KEY,
{field_columns},
{protocol_columns}
)New Fields Added
When the schema gains new fields, the system compares expected columns vs actual and generates:
ALTER TABLE {table} ADD COLUMN {column} {type}Only additive changes are applied automatically.
Type Changes
If a field type changes (e.g., text → integer), the system detects the mismatch and generates a rebuild migration script saved to migrations/manual/:
- SQLite: Uses
PRAGMA foreign_keys=OFF, creates new table, copies data, drops old, renames - PostgreSQL: Wraps in a transaction with
BEGIN/COMMIT - MySQL: Uses
SET FOREIGN_KEY_CHECKS=0
These scripts require manual review and execution.
What Never Happens
- Columns are never dropped — removing a field from TOML does not drop the column
- Data is never modified — existing values remain untouched
- Tables are never dropped — deleting a schema preserves the table
Indexes
Unique indexes are auto-created for:
- Fields with
unique = true - Explicit
[[indexes]]definitions
[[indexes]]
fields = ["slug"]
unique = true
[[indexes]]
fields = ["status", "created_at"]Junction Tables
For many_to_many and many_way relations, junction tables are auto-created:
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)
)Protected Tables
System tables cannot be used as content type tables. These include: users, posts, pages, categories, tags, media, comments, products, orders, wallets, and all other built-in tables.
Reserved route segments (auth, admin, users, media, etc.) cannot be used as singular or plural names.
File Structure
extensions/
content_types/
course.toml # Course content type
instructor.toml # Instructor content type
lesson.toml # Lesson content type
migrations/
manual/ # Type-change rebuild scripts (for manual review)