Collections Builder
The Collections Builder is the no-code surface for defining LumiBase content models. Its Directus-parity contract is explicit: collection metadata, primary key strategy, storage mode, fields, relations, schema diff/apply, SDK typegen, and runtime limitations are all first-class schema data.
1. Collection Lifecycle
Authors create collections through the Studio wizard or by applying raw JSON. The create payload stores collection-level metadata as top-level fields, not hidden meta values:
name,label,pluralLabel,notehidden,system,singletonicon,colorprimaryKeyField,primaryKeyTypestorageModedisplayTemplatesortField,archiveField,archiveValue,unarchiveValueitemDuplicationFields,translationsaccountability,versioningmeta
Collection names are site-scoped and must use snake_case, start with a lowercase letter, and fit the 1-63 character machine-name limit.
2. Primary Keys
Each collection has a logical primary key field and type.
primaryKeyType | Current behavior |
|---|---|
nanoid | Default string identifier generated by LumiBase. |
uuid | Service-generated UUID string. |
string | Caller-provided string identifier. |
integer | Reserved for materialized/physical sequence-backed storage; blocked for JSONB collections. |
bigInteger | Reserved for materialized/physical sequence-backed storage; blocked for JSONB collections. |
Studio blocks unsupported primary key and storage mode combinations before submit. The backend also validates them so raw JSON and SDK callers receive a precise validation error.
3. System Fields
Compiled schemas expose immutable system fields separately from user-defined fields. Studio renders them in a locked group and allows only safe presentation overrides such as display, hidden, readonly, width, and translations.
| Field | Type | Purpose |
|---|---|---|
id | string | Primary item identifier. |
status | string | Workflow status for draft/published/archive flows. |
sort | integer | Manual ordering value. |
user_created | string | User that created the item. |
user_updated | string | User that last updated the item. |
created_at | datetime | Creation timestamp. |
updated_at | datetime | Last update timestamp. |
deleted_at | datetime | Soft-delete timestamp. |
Raw schema output keeps user fields in fields and compiled system fields in systemFields so tooling can distinguish authored schema from generated runtime fields.
4. Fields And Layout
The Fields tab supports Directus-like metadata for each field:
- Basics:
name,label,note,type,interface,display. - Behavior:
required,nullable,readonly,hidden,encrypted,versioned,rawEnabled. - Storage hints:
unique,indexed,searchable,length,precision,scale,special. - UI and validation:
options,displayOptions,validation,conditions,translations,width,group,sortOrder.
The Studio inspector preserves unknown JSON configuration so forward-compatible options are not lost when older Studio builds edit a field.
5. Relations
Relations are first-class schema resources. Each relation stores:
manyCollection,manyFieldoneCollection,oneFieldjunctionCollectiontype:m2o,o2m,m2m, or reservedm2aaliasField,relatedDisplayTemplate,junctionManyField,junctionOneFieldsortField,onDelete,meta
The backend validates referenced collections and fields, blocks unsafe collection deletion while relations still depend on either side, and includes relation changes in schema diff/apply results.
6. Raw JSON, Diff, And Apply
Raw JSON editing uses the same backend contract as the SDK:
{
"name": "posts",
"label": "Posts",
"primaryKeyField": "id",
"primaryKeyType": "nanoid",
"storageMode": "jsonb",
"displayTemplate": "{{title}} — {{status}}",
"fields": [
{
"name": "title",
"type": "string",
"interface": "input",
"required": true,
"nullable": false,
"width": "full"
}
],
"relations": []
}
Use POST /api/v1/collections/diff to preview a schema change. Use PUT /api/v1/collections/{name}/schema to apply it. Apply computes the same diff, validates fields and relations, runs transactionally when the database runtime supports transactions, invalidates schema/permission/typegen caches, and emits a schema.changed event.
Diff entries include:
risk:low,medium, orhighruntimeImpact:cache_invalidation,permission_recompile,typegen_rebuild,data_migration_required,relation_reindex, orstorage_runtime_change- changed collection metadata, fields, and relations
Studio's Raw JSON tab disables apply until preview has run, then shows risk, runtime impact, and the raw diff.
7. Storage Modes
Every collection has a storageMode. Studio shows the mode as a badge in the collection wizard and keeps the tradeoff visible before authors create or migrate a model.
| Mode | Studio badge | Current behavior | Limitations |
|---|---|---|---|
jsonb | Current | Default logical collection. Items live in the shared items.data JSONB document, so schema changes do not run DDL. | SQL-native unique/index constraints are advisory unless a materialized or physical projection exists. Integer primary keys are blocked in this mode. |
materialized | Optimized | JSONB remains the source of truth while a managed physical projection can serve hot read paths. | Projection freshness, refresh strategy, and indexes must be managed; writes still go through the logical collection. |
physical | Future | Reserved for Directus-like managed physical tables. Schema diff marks this as a storage runtime change. | Not implemented as a general DDL migration engine yet. Requires tenant-safe table naming, rollback, relation/index DDL, and online migration planning. |
external | Future | Reserved for introspected external tables. | Not implemented for writes. Destructive relation actions and DDL must remain limited because LumiBase does not own the table. |
Do not present jsonb as equivalent to Directus physical tables. The current product promise is fast schema evolution first, with materialized projections for performance and a future physical/external decision tracked in docs/en/architecture/physical-collections.md.
8. SDK And Typegen
The SDK exposes schema resources under client.schema:
client.schema.collections.list();
client.schema.fields.rename("posts", "headline", "title", {
type: "string",
interface: "input",
confirmRiskyChange: true,
});
client.schema.relations.create({
manyCollection: "posts",
manyField: "author_id",
oneCollection: "authors",
type: "m2o",
});
client.schema.diff("posts", proposedSchema);
client.schema.apply("posts", proposedSchema);
Legacy flat methods such as schema.listCollections() and schema.upsertField() remain available. SDK errors preserve backend code, path, and risk metadata through LumiError.body.
Typegen manifest version 2 includes primary key metadata, system fields, nullable/required, readonly/generated flags, encrypted field read behavior, and relation descriptors. Generated output includes base collection interfaces and relation-expanded response types such as PostsExpanded.