@@ -4,9 +4,9 @@ description: Declare a Content Engine content type once to get a Postgres table,
44icon : FileCode
55---
66
7- import { File , Files , Folder } from " fumadocs-ui/components/files"
8- import { Tab , Tabs } from " fumadocs-ui/components/tabs"
9- import { TypeTable } from " fumadocs-ui/components/type-table"
7+ import { File , Files , Folder } from ' fumadocs-ui/components/files'
8+ import { Tab , Tabs } from ' fumadocs-ui/components/tabs'
9+ import { TypeTable } from ' fumadocs-ui/components/type-table'
1010
1111Content Engine generates a complete CRUD ecosystem from one declaration: a PostgreSQL table, Zod validation schemas, API endpoints, staff permissions, and AdminCP management screens.
1212
@@ -15,23 +15,23 @@ Content Engine generates a complete CRUD ecosystem from one declaration: a Postg
1515### 1. Define the Content Type
1616
1717``` ts title="plugins/example/src/content/category.ts"
18- import { defineContentType , field } from " @vitnode/core/content"
18+ import { defineContentType , field } from ' @vitnode/core/content'
1919
2020export const categoryContentType = defineContentType ({
21- id: " example.category" ,
22- tableName: " example_categories" ,
21+ id: ' example.category' ,
22+ tableName: ' example_categories' ,
2323 fields: {
2424 name: field .text ({ required: true , minLength: 2 , maxLength: 100 }),
25- slug: field .slug ({ from: " name" , required: true }),
25+ slug: field .slug ({ from: ' name' , required: true }),
2626 },
2727})
2828```
2929
3030### 2. Create the Database Model
3131
3232``` ts title="plugins/example/src/database/categories.ts"
33- import { createContentModel } from " @vitnode/core/content/server"
34- import { categoryContentType } from " @/content/category"
33+ import { createContentModel } from ' @vitnode/core/content/server'
34+ import { categoryContentType } from ' @/content/category'
3535
3636export const categoryContent = createContentModel (categoryContentType )
3737export const example_categories = categoryContent .table
@@ -69,16 +69,14 @@ Your table now exists in PostgreSQL.
6969Add the model to your plugin's ` config.api.ts ` :
7070
7171``` ts title="plugins/example/src/config.api.ts"
72- import { buildApiPlugin } from " @vitnode/core/api/lib/plugin"
73- import { categoryContent } from " ./database/categories"
72+ import { buildApiPlugin } from ' @vitnode/core/api/lib/plugin'
73+ import { categoryContent } from ' ./database/categories'
7474
7575export const exampleApiPlugin = () =>
7676 buildApiPlugin ({
77- pluginId: " @vitnode/example" ,
77+ pluginId: ' @vitnode/example' ,
7878 // [!code ++:3]
79- contentTypes: [
80- categoryContent ,
81- ],
79+ contentTypes: [categoryContent ],
8280 })
8381```
8482
@@ -89,26 +87,30 @@ This immediately registers full CRUD routes under `/api/@vitnode/example/admin/c
8987
9088### 2. Register Screens in the AdminCP
9189
92- Connect the definition in ` src/config.tsx ` :
93-
94- ``` tsx title="plugins/example/src/config.tsx"
95- import { buildPlugin , contentTypeAdmin } from " @vitnode/core/lib/plugin"
96- import { FolderIcon } from " lucide-react"
97- import { categoryContentType } from " ./content/category"
98-
99- export const examplePlugin = () =>
100- buildPlugin ({
101- pluginId: " @vitnode/example" ,
102- // [!code ++:6]
103- contentTypes: [
104- contentTypeAdmin ({
105- definition: categoryContentType ,
106- icon: <FolderIcon />,
107- }),
108- ],
109- })
90+ Connect the definition in ` src/admin/content.tsx ` . The build imports this module
91+ through the generated content registry, so it never reaches a public page:
92+
93+ ``` tsx title="plugins/example/src/admin/content.tsx"
94+ import type { ContentFrontendPluginSource } from ' @vitnode/core/lib/plugin'
95+ import { contentTypeAdmin } from ' @vitnode/core/lib/plugin'
96+ import { FolderIcon } from ' lucide-react'
97+ import { categoryContentType } from ' @/content/category'
98+
99+ export const adminContent = {
100+ pluginId: ' @vitnode/example' ,
101+ // [!code ++:6]
102+ contentTypes: [
103+ contentTypeAdmin ({
104+ definition: categoryContentType ,
105+ icon: <FolderIcon />,
106+ }),
107+ ],
108+ } satisfies ContentFrontendPluginSource
110109```
111110
111+ The sidebar entry comes from ` src/admin/nav.tsx ` the same way - see
112+ [ Plugin frontend modules] ( /docs/dev/content-engine/plugin-registration ) .
113+
112114</Step >
113115<Step >
114116
@@ -151,25 +153,26 @@ You have a complete AdminCP data table with search, sorting, pagination, and mod
151153 id: {
152154 description: " Unique identifier formatted as '<plugin>.<name>'." ,
153155 required: true ,
154- type: " string" ,
156+ type: ' string' ,
155157 },
156158 tableName: {
157159 description: " Postgres table name (e.g. 'example_categories')." ,
158160 required: true ,
159- type: " string" ,
161+ type: ' string' ,
160162 },
161163 fields: {
162- description: " Record containing field descriptors created with field.*." ,
164+ description: ' Record containing field descriptors created with field.*.' ,
163165 required: true ,
164- type: " Record<string, ContentField>" ,
166+ type: ' Record<string, ContentField>' ,
165167 },
166168 publication: {
167- description: " Enables draft/published workflows and publishedAt timestamps." ,
168- type: " { enabled: boolean }" ,
169+ description:
170+ ' Enables draft/published workflows and publishedAt timestamps.' ,
171+ type: ' { enabled: boolean }' ,
169172 },
170173 indexes: {
171- description: " Custom single or composite database indexes." ,
172- type: " IndexDefinition[]" ,
174+ description: ' Custom single or composite database indexes.' ,
175+ type: ' IndexDefinition[]' ,
173176 },
174177 }}
175178/>
0 commit comments