11---
22name : vespertide
3- description : Define database schemas in JSON and generate migration plans. Use this skill when creating or modifying database models, defining tables with columns, constraints, indexes, and foreign keys for Vespertide-based projects.
3+ description : Define database schemas in JSON and generate migration plans. Use this skill when creating or modifying database models, defining tables with columns and inline constraints (primary_key, unique, index, foreign_key) for Vespertide-based projects.
44---
55
66# Vespertide Database Schema Definition
@@ -34,8 +34,7 @@ Models are JSON files in the `models/` directory:
3434 "$schema" : " https://raw.githubusercontent.com/dev-five-git/vespertide/refs/heads/main/schemas/model.schema.json" ,
3535 "name" : " table_name" ,
3636 "columns" : [],
37- "constraints" : [],
38- "indexes" : []
37+ "constraints" : []
3938}
4039```
4140
@@ -46,7 +45,8 @@ Models are JSON files in the `models/` directory:
4645| ` name ` | string | Table name (snake_case) |
4746| ` columns ` | array | Column definitions |
4847| ` constraints ` | array | Table-level constraints (can be empty ` [] ` ) |
49- | ` indexes ` | array | Index definitions (can be empty ` [] ` ) |
48+
49+ ** Note** : The ` indexes ` field has been removed. Use inline ` index ` fields on columns instead (see Inline Constraints below).
5050
5151## Column Definition
5252
@@ -188,13 +188,24 @@ Reference actions: `"Cascade"`, `"Restrict"`, `"SetNull"`, `"SetDefault"`, `"NoA
188188]
189189```
190190
191- ## Table-Level Indexes
191+ ## Indexes
192+
193+ ** Prefer inline indexes** on column definitions instead of table-level indexes:
192194
193195``` json
194- "indexes" : [
195- { "name" : " idx_user_email" , "columns" : [" email" ], "unique" : false },
196- { "name" : " idx_composite" , "columns" : [" user_id" , " created_at" ], "unique" : false }
197- ]
196+ {
197+ "name" : " email" ,
198+ "type" : " text" ,
199+ "nullable" : false ,
200+ "index" : true
201+ }
202+ ```
203+
204+ For composite indexes, use the same index name on multiple columns:
205+
206+ ``` json
207+ { "name" : " user_id" , "type" : " integer" , "nullable" : false , "index" : [" idx_user_date" ] },
208+ { "name" : " created_at" , "type" : " timestamp" , "nullable" : false , "index" : [" idx_user_date" ] }
198209```
199210
200211## Examples
@@ -211,8 +222,7 @@ Reference actions: `"Cascade"`, `"Restrict"`, `"SetNull"`, `"SetDefault"`, `"NoA
211222 { "name" : " name" , "type" : " text" , "nullable" : false },
212223 { "name" : " created_at" , "type" : " timestamptz" , "nullable" : false , "default" : " NOW()" }
213224 ],
214- "constraints" : [],
215- "indexes" : []
225+ "constraints" : []
216226}
217227```
218228
@@ -230,8 +240,7 @@ Reference actions: `"Cascade"`, `"Restrict"`, `"SetNull"`, `"SetDefault"`, `"NoA
230240 { "name" : " published" , "type" : " boolean" , "nullable" : false , "default" : " false" },
231241 { "name" : " created_at" , "type" : " timestamptz" , "nullable" : false , "default" : " NOW()" }
232242 ],
233- "constraints" : [],
234- "indexes" : []
243+ "constraints" : []
235244}
236245```
237246
@@ -251,8 +260,7 @@ Reference actions: `"Cascade"`, `"Restrict"`, `"SetNull"`, `"SetDefault"`, `"NoA
251260 ],
252261 "constraints" : [
253262 { "type" : " check" , "name" : " check_total_positive" , "expr" : " total_amount >= 0" }
254- ],
255- "indexes" : []
263+ ]
256264}
257265```
258266
@@ -264,32 +272,30 @@ Reference actions: `"Cascade"`, `"Restrict"`, `"SetNull"`, `"SetDefault"`, `"NoA
264272 "name" : " user_role" ,
265273 "columns" : [
266274 { "name" : " user_id" , "type" : " integer" , "nullable" : false , "primary_key" : true , "foreign_key" : { "ref_table" : " user" , "ref_columns" : [" id" ], "on_delete" : " Cascade" } },
267- { "name" : " role_id" , "type" : " integer" , "nullable" : false , "primary_key" : true , "foreign_key" : { "ref_table" : " role" , "ref_columns" : [" id" ], "on_delete" : " Cascade" } },
275+ { "name" : " role_id" , "type" : " integer" , "nullable" : false , "primary_key" : true , "foreign_key" : { "ref_table" : " role" , "ref_columns" : [" id" ], "on_delete" : " Cascade" }, "index" : true },
268276 { "name" : " assigned_at" , "type" : " timestamptz" , "nullable" : false , "default" : " NOW()" }
269277 ],
270- "constraints" : [],
271- "indexes" : [
272- { "name" : " idx_user_role_role" , "columns" : [" role_id" ], "unique" : false }
273- ]
278+ "constraints" : []
274279}
275280```
276281
277282## Guidelines
278283
2792841 . ** Always include ` $schema ` ** for IDE validation and autocompletion
2802852 . ** Always specify ` nullable ` ** on every column
281- 3 . ** Always include empty arrays** for ` constraints ` and ` indexes ` even if unused
282- 4 . ** Add indexes on foreign key columns** for query performance
283- 5 . ** Use named constraints** (especially CHECK) for easier management
284- 6 . ** Naming conventions** :
286+ 3 . ** Always include empty array** for ` constraints ` even if unused
287+ 4 . ** Prefer inline constraints** (` primary_key ` , ` unique ` , ` index ` , ` foreign_key ` ) over table-level definitions
288+ 5 . ** Use inline ` index ` on foreign key columns** for query performance (e.g., ` "index": true ` )
289+ 6 . ** Use named constraints** (especially CHECK) for easier management
290+ 7 . ** Naming conventions** :
285291 - Tables: ` snake_case ` (e.g., ` user_role ` )
286292 - Columns: ` snake_case ` (e.g., ` created_at ` )
287293 - Indexes: ` idx_{table}_{columns} `
288294 - Unique constraints: ` uq_{table}_{columns} `
289295 - Foreign keys: ` fk_{table}_{ref_table} `
290296 - Check constraints: ` check_{description} `
291- 7 . ** Timestamp columns** :
297+ 8 . ** Timestamp columns** :
292298 - ` created_at ` : ` "default": "NOW()" ` , ` nullable: false `
293299 - ` updated_at ` : ` nullable: true ` (managed by application)
294- 8 . ** Boolean defaults** : Use string format ` "true" ` or ` "false" `
295- 9 . ** Adding NOT NULL columns** to existing tables requires either a ` default ` value or ` fill_with ` in migration
300+ 9 . ** Boolean defaults** : Use string format ` "true" ` or ` "false" `
301+ 10 . ** Adding NOT NULL columns** to existing tables requires either a ` default ` value or ` fill_with ` in migration
0 commit comments