Appearance
Collections & Fields Management
Overview
Collections are database tables (or virtual folder groups). Fields are their columns. Both are managed at runtime — you can create, modify, and delete schema objects without code changes or restarts.
- CollectionsService (
src/services/collections.ts) manages table creation and metadata. - FieldsService (
src/services/fields.ts) manages column creation and Directus-compatible metadata.
Collections
Data Model
Table: odp_collections (metadata only — the actual table is created in the DB)
| Column | Type | Description |
|---|---|---|
collection | varchar | Collection name (= table name) |
icon | varchar | UI icon |
note | text | Description shown in app |
display_template | varchar | Template string for item display |
hidden | boolean | Hidden from app panel |
singleton | boolean | Only one item exists |
translations | json | i18n translations for name/description |
archive_field | varchar | Field used for soft delete archiving |
archive_app_filter | boolean | Show archive filter in app |
archive_value | varchar | Value meaning "archived" |
unarchive_value | varchar | Value meaning "active" |
sort_field | varchar | Field for manual drag-to-sort |
accountability | varchar | Audit log mode: all, activity, null |
item_duplication_fields | json | Fields to copy when duplicating items |
group | varchar | Parent folder collection name |
collapse | varchar | UI collapse state |
sort | integer | Sort order in sidebar |
versioning | boolean | Enable content versioning |
versioning_delta_options | json | Versioning configuration |
Collection Endpoints
POST /collections
Create a new collection. Admin only.
Request Body
json
{
"collection": "articles",
"meta": {
"icon": "article",
"note": "Blog articles",
"singleton": false,
"sort_field": "sort"
},
"fields": [
{
"field": "id",
"type": "uuid",
"meta": { "hidden": true, "readonly": true },
"schema": { "is_primary_key": true, "has_auto_increment": false }
},
{
"field": "title",
"type": "string",
"meta": { "interface": "input", "required": true }
},
{
"field": "status",
"type": "string",
"meta": {
"interface": "select-dropdown",
"options": { "choices": [
{ "text": "Draft", "value": "draft" },
{ "text": "Published", "value": "published" }
]}
},
"schema": { "default_value": "draft" }
}
],
"schema": { "name": "articles" }
}| Property | Description |
|---|---|
collection | Table name (snake_case, no spaces) |
meta | Visual/UI configuration |
fields | Initial fields to create (array) |
schema.name | DB table name (usually same as collection) |
folder: true | Create a virtual folder (no DB table) |
Response 200 — Returns the full collection object.
GET /collections
List all collections.
Auth required: App access
Returns collections the user has at least read permission on (or all for admins). Response uses Directus-compatible format.
GET /collections/:collection
Read a single collection definition.
Auth required: App access
Response 200
json
{
"data": {
"collection": "articles",
"meta": {
"icon": "article",
"singleton": false,
"sort_field": "sort"
},
"schema": {
"name": "articles"
}
}
}PATCH /collections/:collection
Update collection metadata or schema. Admin only.
Request Body
json
{
"meta": {
"note": "Updated description",
"hidden": false
}
}DELETE /collections/:collection
Delete the collection and its table. Admin only.
Response 204
This drops the database table and removes all metadata, fields, and permissions for this collection.
Fields
Data Model
Fields have two components:
schema— the actual DB column definition (type, nullability, default, etc.)meta— UI/display configuration stored inodp_fields
Table: odp_fields (meta only — schema is read from DB information_schema)
| Column | Type | Description |
|---|---|---|
id | integer | Primary key |
collection | varchar | Collection name |
field | varchar | Column name |
special | json | Special handling (e.g., uuid, cast-boolean) |
interface | varchar | UI interface component |
options | json | Interface-specific options |
display | varchar | Display component |
display_options | json | Display component options |
readonly | boolean | Read-only in app |
hidden | boolean | Hidden in app |
sort | integer | Field order in app |
width | varchar | Column width: half, full, fill |
translations | json | i18n field labels |
note | text | Help text |
conditions | json | Conditional visibility rules |
required | boolean | Required validation |
group | varchar | Field group/panel name |
validation | json | Custom validation rules |
validation_message | text | Error message for validation |
Field Endpoints
POST /fields/:collection
Create a new field. Admin only.
Request Body
json
{
"field": "published_at",
"type": "timestamp",
"meta": {
"interface": "datetime",
"display": "datetime",
"readonly": false,
"hidden": false,
"note": "When this article was published"
},
"schema": {
"is_nullable": true,
"default_value": null
}
}Field Types
| Type | DB Column | Notes |
|---|---|---|
string | VARCHAR | Configurable length |
text | TEXT | Long text |
integer | INTEGER | |
bigInteger | BIGINT | |
float | FLOAT | |
decimal | DECIMAL | |
boolean | BOOLEAN | |
date | DATE | |
time | TIME | |
timestamp | TIMESTAMP | Auto-converts to ISO 8601 |
dateTime | DATETIME | |
uuid | UUID / CHAR(36) | |
json | JSON/TEXT | Stored as JSON |
csv | VARCHAR | Comma-separated values |
hash | VARCHAR | Stored as hash |
alias | (none) | Virtual field (no DB column) |
Response 200 — Returns the field in Directus-compatible format.
GET /fields
Read all fields across all collections.
Auth required: App access
GET /fields/:collection
Read all fields for a specific collection.
Auth required: App access
Response 200
json
{
"data": [
{
"collection": "articles",
"field": "id",
"type": "uuid",
"meta": { "hidden": true, "readonly": true },
"schema": { "is_primary_key": true, "is_nullable": false }
},
{
"collection": "articles",
"field": "title",
"type": "string",
"meta": { "interface": "input", "required": true },
"schema": { "max_length": 255, "is_nullable": false }
}
]
}GET /fields/:collection/:field
Read a single field.
Auth required: App access
PATCH /fields/:collection/:field
Update a field's type, schema, or meta. Admin only.
Request Body
json
{
"type": "text",
"meta": {
"interface": "input-rich-text-html",
"note": "Rich text content"
},
"schema": {
"is_nullable": true
}
}All three top-level keys (type, meta, schema) are optional.
DELETE /fields/:collection/:field
Delete a field and its column. Admin only.
Response 204
Drops the database column and removes meta row.
Business Logic Notes
- System collections (prefixed with
odp_) are read-only for non-admin users. Admins can read schema but cannot delete system collections via the API. - Schema caching: The
SchemaServicecaches the schema overview. Changes via these endpoints invalidate the cache automatically. - Directus compatibility: Field and collection responses are formatted via
toDirectusFieldFormat()andtoDirectusCollectionFormat()utilities for backward compatibility with Directus SDK clients. - Folder collections: Created with
folder: true— no database table is created. Used for organizing collections in the sidebar.