Field Metadata
Where it lives
JSON Pointer:/moduleMetadata/models/fields
JSONPath:$.moduleMetadata.models[*].fields[*]
Parent:modelsin themoduleMetadataof the root of the metadata file
Overviewβ
Every SolidX model is composed of fields. Fields in SolidX go over and above the standard fields one expects, instead we treat fields as semantic attributes with relevance to how the users interact with that data in our admin interface.
π For a conceptual overview of fields supported in a model, see Field Management Documentation.
Example: Institute + Fee Type Model fieldsβ
Field Schema
{
"moduleMetadata": {
..., // Module metadata
"models": [ // Model metadata array
{ // Institute model metadata
"singularName": "institute",
"pluralName": "institutes",
"displayName": "Institute",
"description": "Institute records",
"dataSource": "default",
"dataSourceType": "postgres",
"tableName": "fees_portal_institute",
"userKeyFieldUserKey": "instituteName",
"isChild": false,
"enableAuditTracking": true,
"enableSoftDelete": false,
"draftPublishWorkflow": false,
"internationalisation": false,
"fields": [ // Institute model fields metadata
{
"name": "instituteName",
"displayName": "Institute Name",
"description": null,
"type": "shortText",
"ormType": "varchar",
"isSystem": false,
"defaultValue": null,
"min": null,
"max": null,
"required": true,
"unique": true,
"index": true,
"private": false,
"encrypt": false,
"encryptionType": null,
"decryptWhen": null,
"columnName": null,
"isUserKey": true,
"enableAuditTracking": false
},
..., // Other fields
]
},
{ // Fee Type model metadata
"singularName": "feeType",
"pluralName": "feeTypes",
"displayName": "Fee Type",
"description": "Fee Type records",
"dataSource": "default",
"dataSourceType": "postgres",
"tableName": "fees_portal_fee_type",
"userKeyFieldUserKey": "feeTypeUserKey",
"isChild": false,
"enableAuditTracking": true,
"enableSoftDelete": false,
"draftPublishWorkflow": false,
"internationalisation": false,
"fields": [ // Fee Type model fields metadata
{
"name": "institute",
"displayName": "Institute",
"description": null,
"type": "relation",
"ormType": "integer",
"isSystem": false,
"relationType": "many-to-one",
"relationCoModelFieldName": "feeTypes",
"relationCreateInverse": true,
"relationCoModelSingularName": "institute",
"relationCoModelColumnName": null,
"relationModelModuleName": "fees-portal",
"relationCascade": "cascade",
"required": true,
"unique": false,
"index": false,
"private": false,
"encrypt": false,
"encryptionType": null,
"decryptWhen": null,
"columnName": null,
"relationJoinTableName": null,
"isRelationManyToManyOwner": null,
"relationFieldFixedFilter": "",
"enableAuditTracking": false
},
... // Other fields
]
},
..., // Other models
]
},
... // Other metadata
}
Field Type (type)β
This is the most important attribute of a field.
It determines the behavior, validation, storage, and UI options for the field.
Numeric Typesβ
| Value | Reference | Example |
|---|---|---|
int | Integer Field | See Example |
bigint | BigInt Field | See Example |
decimal | Decimal Field | See Example |
Text Typesβ
| Value | Reference | Example |
|---|---|---|
shortText | Short Text Field | See Example |
longText | Long Text Field | See Example |
richText | Rich Text Field | See Example |
json | JSON Field | See Example |
Booleanβ
| Value | Reference | Example |
|---|---|---|
boolean | Boolean Field | See Example |
Date / Time Typesβ
| Value | Reference | Example |
|---|---|---|
date | Date Field | See Example |
datetime | Datetime Field | See Example |
time | Time Field | See Example |
Relation Typesβ
| Value | Reference | Example |
|---|---|---|
many-to-one | Many To One | See Example |
one-to-many | One To Many | See Example |
many-to-many | Many To Many | See Example |
Media Typesβ
| Value | Reference | Example |
|---|---|---|
mediaSingle | Single Media Field | See Example |
mediaMultiple | Multiple Media Field | See Example |
Specialized Typesβ
| Value | Reference | Example |
|---|---|---|
email | Email Field | See Example |
password | Password Field | See Example |
Selection Typesβ
| Value | Reference | Example |
|---|---|---|
selectionStatic | Static Selection Field | See Example |
selectionDynamic | Dynamic Selection Field | See Example |
Computedβ
| Value | Reference | Example |
|---|---|---|
computed | Computed Field | See Example |
Field Metadata Examplesβ
Numeric Typesβ
1. intβ
Purpose: For whole numbers (positive/negative)
Database: integer column
UI Component: Number input field
Use Cases: Counts, quantities, IDs, rankings
{
"name": "studentCount",
"displayName": "Student Count",
"type": "int",
"ormType": "integer",
"min": 0,
"max": 10000,
"defaultValue": 0,
"required": true
}
Key Properties:
min: Lower boundmax: Upper bounddefaultValue: Initial value on create
2. decimalβ
Purpose: For decimal/floating point numbers
Database: decimal column
UI Component: Decimal input field
Use Cases: Prices, percentages, measurements, financial amounts
{
"name": "feeAmount",
"displayName": "Fee Amount",
"type": "decimal",
"ormType": "decimal",
"min": 0,
"max": 100000,
"defaultValue": "0.00",
"required": true,
}
Key Properties:
min: Lower boundmax: Upper bounddefaultValue: Initial value on create
3. bigint (TODO)β
Text Typesβ
1. shortTextβ
Purpose: For shorter text content (typically up to 1000 characters)
Database: varchar column
UI Component: Text input field
Use Cases: Names, titles, identifiers, short descriptions
{
"name": "instituteName",
"displayName": "Institute Name",
"type": "shortText",
"ormType": "varchar",
"min": null,
"max": 256,
"required": true,
"unique": true,
"index": true,
"isUserKey": true
}
Key Properties:
min/max: Character limitsunique: Enforce uniquenessindex: Database performance optimizationisUserKey: Use as record identifier
2. longTextβ
Purpose: For multi-line text content of any length
Database: text column
UI Component: Textarea field
Use Cases: Descriptions, comments, notes, multi-paragraph content
{
"name": "description",
"displayName": "Description",
"type": "longText",
"ormType": "text",
"regexPattern": "^[a-zA-Z0-9\\s]*$",
"regexPatternNotMatchingErrorMsg": "Only alphanumeric characters and spaces allowed",
"min": 10,
"max": 5000,
"required": false
}
Key Properties:
regexPattern: Validation patternregexPatternNotMatchingErrorMsg: Custom validation error message- Supports longer content than
shortText
3. richTextβ
Purpose: For formatted text with HTML support
Database: text column
UI Component: Rich text editor (HTML)
Use Cases: Content with formatting, FAQs, policies, documentation
{
"name": "privacyPolicy",
"displayName": "Privacy Policy",
"type": "richText",
"ormType": "text",
"required": false,
}
Key Properties:
- Supports HTML formatting
- No length restrictions
- Rich editing capabilities in UI
Booleanβ
1. booleanβ
Purpose: For true/false values
Database: boolean column
UI Component: Checkbox or toggle switch
Use Cases: Flags, settings, yes/no options, status indicators
{
"name": "isActive",
"displayName": "Is Active",
"type": "boolean",
"ormType": "boolean",
"defaultValue": true,
"required": true
}
Key Properties:
defaultValue:trueorfalse- Simple on/off state management
Date / Time Typesβ
1. dateβ
Purpose: For date values only (no time)
Database: date column
UI Component: Date picker
Use Cases: Birth dates, deadlines, event dates
{
"name": "dueDate",
"displayName": "Due Date",
"type": "date",
"ormType": "date",
"required": true,
"defaultValue": null
}
2. datetimeβ
Purpose: For date and time values
Database: timestamp column
UI Component: DateTime picker
Use Cases: Created/updated timestamps, scheduled events, appointments
{
"name": "registeredAt",
"displayName": "Registered At",
"type": "datetime",
"ormType": "timestamp",
"required": true,
"enableAuditTracking": true
}
3. time (TODO)β
Relation Typesβ
Purpose: Establish relationships between models
Database: Foreign key columns or junction tables
UI Component: Related record selector
Use Cases: Parent-child relationships, data linking
Supported Types i.e attribute (relationType):
many-to-one: Many records link to one parent (e.g., Orders β Customer)one-to-many: One record has many children (e.g., Customer β Orders)many-to-many: Many records link to many others via a junction table (e.g., Students β Courses)
1. Many-to-One Relation (Child β Parent)β
{
"name": "institute",
"displayName": "Institute",
"type": "relation",
"relationType": "many-to-one",
"relationCoModelSingularName": "institute",
"relationCoModelColumnName": null,
"relationModelModuleName": "fees-portal",
"relationCascade": "cascade",
"required": true
}
2. One-to-Many Relation (Parent β Children)β
{
"name": "feeTypes",
"displayName": "Fee Types",
"type": "relation",
"relationType": "one-to-many",
"relationCoModelSingularName": "feeType",
"relationCoModelFieldName": "institute",
"relationCoModelColumnName": "instituteId",
"relationModelModuleName": "fees-portal",
"relationCreateInverse": true
}
3. Many-to-Many Relationβ
{
"name": "categories",
"displayName": "Categories",
"type": "relation",
"relationType": "many-to-many",
"relationCoModelSingularName": "category",
"relationModelModuleName": "fees-portal",
"relationJoinTableName": "fee_category_junction",
"isRelationManyToManyOwner": true,
"relationCreateInverse": true
}
Key Properties:
relationType: "one-to-many", "many-to-one", "many-to-many"relationCoModelSingularName: Target model namerelationCoModelColumnName: Foreign key column namerelationJoinTableName: Junction table for many-to-manyrelationCascade: Cascade behavior for deletesrelationCreateInverse: Auto-create inverse relationship
Give an example of inverse vs non-inverse relation creation (TODO)
Media Typesβ
1. mediaSingleβ
Purpose: Single file/image upload
UI Component: File upload with preview
Use Cases: Profile pictures, logos, single documents
{
"name": "logo",
"displayName": "Logo",
"type": "mediaSingle",
"mediaTypes": ["image"],
"mediaMaxSizeKb": 5120,
"mediaStorageProviderUserKey": "default-aws-s3",
"required": true
}
2. mediaMultipleβ
Purpose: Multiple file uploads
UI Component: Multi-file upload with gallery
Use Cases: Photo galleries, document collections, attachments
{
"name": "documents",
"displayName": "Documents",
"type": "mediaMultiple",
"mediaTypes": ["image", "document", "pdf"],
"mediaMaxSizeKb": 10240,
"mediaStorageProviderUserKey": "default-aws-s3",
"required": false
}
Key Properties:
mediaTypes: Array of allowed file typesmediaMaxSizeKb: Maximum file size per filemediaStorageProviderUserKey: Storage configuration reference
Specialized Typesβ
1. emailβ
Purpose: Email addresses with validation
Database: varchar
UI Component: Email input field
Use Cases: User contact information, notifications
{
"name": "email",
"displayName": "Email Address",
"type": "email",
"ormType": "varchar",
"required": true,
"unique": true,
"index": true
}
2. jsonβ
Purpose: Store complex JSON data structures
Database: text/jsonb
UI Component: JSON editor or code field
Use Cases: Flexible data structures, API responses, configurations
{
"name": "metadata",
"displayName": "Metadata",
"type": "json",
"ormType": "jsonb",
"required": false,
"defaultValue": "{}"
}
3. passwordβ
Purpose: Secure password storage with hashing
Database: varchar (hashed)
UI Component: Password input field
Use Cases: User authentication, secure credentials
{
"name": "password",
"displayName": "Password",
"type": "password",
"ormType": "varchar",
"min": 8,
"max": 128,
"required": true,
"regexPattern": "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$",
}
Selection Typesβ
1. selectionStaticβ
Purpose: Dropdown with predefined options
Database: varchar column
UI Component: Dropdown/select field
Use Cases: Status options, categories, fixed lists
{
"name": "latePaymentFeesType",
"displayName": "Late Payment Fees Type",
"type": "selectionStatic",
"ormType": "varchar",
"selectionStaticValues": [
"None:None",
"Percent:Percent",
"Absolute:Absolute"
],
"selectionValueType": "string",
"defaultValue": "None",
"required": true
}
Format: "value:label" where value is stored in DB, label is displayed in UI
2. selectionDynamicβ
Purpose: Dropdown populated from API/database query
Database: varchar column
UI Component: Dynamic dropdown field
Use Cases: Related data, user lists, dynamic categories
{
"name": "studentId",
"displayName": "Student",
"type": "selectionDynamic",
"ormType": "varchar",
"selectionDynamicProvider": "StudentListProvider",
"selectionDynamicProviderCtxt": "{\"filters\": {\"isActive\": true}}",
"required": true
}
Key Properties:
selectionDynamicProvider: Provider class responsible for returning the dynamic dropdown optionsselectionDynamicProviderCtxt: JSON context/config passed to the provider
Computedβ
1. computedβ
Purpose: Auto-calculated values from other fields
Database: varchar/decimal/etc. (based on result type)
UI Component: Read-only display field
Use Cases: Calculated totals, formatted names, derived values
{
"name": "fullName",
"displayName": "Full Name",
"type": "computed",
"ormType": "varchar",
"computedFieldValueType": "string",
"computedFieldTriggerConfig": [
{
"modelName": "student",
"moduleName": "fees-portal",
"operations": ["before-insert", "before-update"]
}
],
"computedFieldValueProvider": "ConcatEntityComputedFieldProvider",
"computedFieldValueProviderCtxt": "{\"fields\":[\"firstName\",\"lastName\"],\"separator\":\" \"}",
"required": true
}
Key Properties:
computedFieldValueType: Result data typecomputedFieldTriggerConfig: When to recalculatecomputedFieldValueProvider: Computation service provider classcomputedFieldValueProviderCtxt: JSON configuration for provider
Common Field Metadata Attributesβ
All field types support these common properties:
Core Propertiesβ
name: Internal field reference (camelCase)displayName: User-friendly UI labeldescription: Optional documentationtype: Field type identifierormType: Database column typeisSystem: System-managed field flagrequired: Mandatory field flagunique: Uniqueness constraintindex: Database index creationprivate: Hidden from UI flag (Not yet implemented)defaultValue: Default field value
Security Propertiesβ
encrypt: Enable field encryption (Not yet implemented)encryptionType: Encryption method (AES, bcrypt, etc.) (Not yet implemented)decryptWhen: When to decrypt ("always", "admin_only", "never") (Not yet implemented)
Database Propertiesβ
columnName: Custom database column nameenableAuditTracking: Include in audit logs
Validation Propertiesβ
min/max: Value/length constraintsregexPattern: Custom validation patternregexPatternNotMatchingErrorMsg: Custom error message
Field Metadata Attributesβ
name (string, required)β
Name of the field (column/property).
Default: N/A
displayName (string, required)β
Human-readable label for UI and docs.
Default: N/A
description (string, optional)β
Short help/purpose text shown in UI or docs.
Default: N/A
type (SolidFieldType, required)β
Refer to Field Type section above.
Default: N/A
modelId (number, optional)β
Numeric id of the owning model (internal linkage).
Default: N/A
ormType (PSQLType, optional)β
Override database column type based on dataSourcetype and field type. Use only when the default mapping from type is insufficient.
| Field Type | Postgres (PSQLType) | MSSQL (MSSQLType) |
|---|---|---|
| int | integer | int |
| bigint | bigint | bigint |
| decimal | decimal | numeric, decimal |
| shortText | varchar | varchar, nvarchar |
| longText | text | nvarchar |
| richText | text | nvarchar |
| json | simplejson, json, jsonb | simplejson, nvarchar |
| boolean | boolean | bit |
| date | date | date |
| datetime | timestamp, timestamptz | datetime, datetime2 |
| time | time, timestamp, timestamptz | time |
| relation | integer | int |
| mediaSingle | varchar | varchar |
| mediaMultiple | varchar | varchar |
varchar | nvarchar | |
| password | varchar | nvarchar |
| selectionStatic | varchar | nvarchar |
| selectionDynamic | varchar | nvarchar |
| computed | varchar | nvarchar |
| uuid | varchar | uniqueidentifier |
defaultValue (string, optional)β
Literal default value applied on create.
Default: N/A
regexPattern (string, optional)β
Validation pattern for textual inputs.
Applies to: shortText, longText, email, password
Default: N/A
regexPatternNotMatchingErrorMsg (string, optional)β
Custom error message when regexPattern fails.
Default: N/A
required (boolean, optional)β
Marks field as mandatory.
Default: false
unique (boolean, optional)β
Enforces uniqueness.
Default: false
encrypt (boolean, optional)β
Enable symmetric encryption-at-rest for this field.
Default: false
Info
Feature coming soon!
encryptionType (enum, optional)β
Only if encrypt = true.
Values:
- aes-128
- aes-256
Default: aes-256 (recommended)
Info
Feature coming soon!
decryptWhen (enum, optional)β
Only if encrypt = true. Controls when plaintext is produced.
Values:
- before-transit
- after-transit
Default: after-transit
Info
Feature coming soon!
index (boolean, optional)β
Add an index for search/sort (where supported).
Not applicable to: richText, longText
Default: false
max (number, optional)β
Upper bound (number/date) or maximum length (text/json).
Applies to: shortText, longText, richText, json, int, decimal, date, datetime, time
Default: N/A
min (number, optional)β
Lower bound (number/date) or minimum length (text/json).
Applies to: shortText, longText, richText, json, int, decimal, date, datetime, time
Default: N/A
private (boolean, optional)β
Exclude from default listings/exports; require elevated access.
Default: false
Info
Feature coming soon!
mediaTypes (MediaType[], optional)β
Allowlist of media categories.
Applies to: mediaSingle, mediaMultiple
Values:
- image
- audio
- video
- file
Default: All sensible for the field type
mediaMaxSizeKb (number, optional)β
Max upload size per item in kilobytes.
Applies to: mediaSingle, mediaMultiple
Default: N/A
mediaStorageProviderId (number, optional)β
Numeric id of configured media storage provider.
Applies to: mediaSingle, mediaMultiple
Default: Module/provider default
mediaStorageProviderUserKey (string, optional)β
Name/userKey of configured media storage provider.
Applies to: mediaSingle, mediaMultiple
Default: default-filesystem
Info
By default, SolidX applications gets seeded with 2 media storage providers i.e default-filesystem and default-aws-s3. You can create more providers as per your requirements. You can refer to the Storage Provider Documentation for more details.
relationType (RelationType, optional)β
Kind of relation.
Applies to: relation
Values:
- many-to-one
- many-to-many
- one-to-many
Default: N/A
relationCoModelSingularName (string, optional)β
singularName of the related co-model.
Applies to: relation
Default: N/A
relationCreateInverse (boolean, optional)β
Generate inverse side on co-model.
Applies to: relation
Default: false
Warning
Currently we auto-create the inverse side of the field metadata on the co-model. In future releases, we will get rid of the inverse field auto-creation and instead have the user explicitly create the inverse field on the co-model. This is to ensure that the user has full control on how the inverse field is created on the co-model and keep things explicit and simple
relationCascade (CascadeType, optional)β
Only if type = relation and relationCreateInverse = true.
Cascade behavior for persistence i.e (create/update) and deletion.
Applies to: relation
Values:
- set null
- restrict
- cascade
Default: restrict (recommended explicitness)
relationModelModuleName (string, optional)β
Only if type = relation and relationCreateInverse = true and the related co-model lives in a different module.
Module name if the related co-model lives in a different module.
Applies to: relation
Default: Current module
relationCoModelFieldName (string, mandatory for many-to-many)β
Only if type = relation and relationCreateInverse = true.
For m2m or cross-model relations, the other side's field name.
Auto-inferred for many-to-one but required for many-to-many.
Applies to: relation
Default: Auto-inferred for many-to-one
isRelationManyToManyOwner (boolean, mandatory for many-to-many)β
Only if type = relation and relationType = many-to-many.
Marks this side as the owner of the many-to-many.
At least one side must be the owner, otherwise the many-to-many relation will not work.
Applies to: relation (many-to-many)
Default: false
Info
TODO: change default to true in future releases
relationFieldFixedFilter (string, optional)β
Fixed filter (JSON) applied when fetching related records from the admin ui. This can be used to apply static as well as dynamic filters when we want to conditionally filter the values shown for the related records
The filter is a JSON object of schema type BasicFilterDto:
Filter schema
export enum SoftDeleteFilter {
INCLUSIVE = "inclusive",
EXCLUSIVE = "exclusive",
}
export class BasicFilterDto extends PaginationQueryDto {
@IsOptional()
@ApiProperty({ description: "Fields" })
readonly fields?: string[];
@IsOptional()
@ApiProperty({ description: "sort" })
readonly sort?: string[];
@IsOptional()
@ApiProperty({ description: "groupBy" })
readonly groupBy?: string[];
@IsOptional()
@ApiProperty({ description: "populate" })
readonly populate?: string[];
@IsOptional()
@ApiProperty({ description: "populateMedia" })
readonly populateMedia?: string[];
@IsOptional()
@IsEnum(SoftDeleteFilter)
@ApiProperty({
description: "showSoftDeleted",
enum: SoftDeleteFilter,
})
readonly showSoftDeleted?: SoftDeleteFilter;
@IsOptional()
@ApiProperty({ description: "populateGroup" })
readonly populateGroup?: boolean;
@IsOptional()
@ApiProperty({ description: "groupFilter" })
groupFilter?: BasicFilterDto
@IsOptional()
@ApiProperty({ description: "locale" })
readonly locale?: string;
@IsOptional()
@ApiProperty({ description: "status publish draft" })
readonly status?: string;
}
export class PaginationQueryDto {
constructor(limit: number, offset: number) {
this.limit = limit;
this.offset = offset;
}
@IsOptional()
@Type(() => Number)
@IsPositive()
limit?: number = 10;
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(0)
offset?: number = 0;
@IsOptional()
filters?: Record<string, any>;
}
Applies to: relation
Default: N/A
selectionDynamicProvider (string, optional)β
Provider identifier for loading dynamic options.
Applies to: selectionDynamic
Default: N/A
selectionDynamicProviderCtxt (string, optional)β
Context/config passed to the dynamic provider.
Applies to: selectionDynamic
Default: N/A
selectionStaticValues (string[], optional)β
List of static options in key:Label format.
Applies to: selectionStatic
Default: N/A
selectionValueType (enum, optional)β
Primitive type of selection values.
Applies to: selectionStatic, selectionDynamic
Values:
- string
- int
Default: string
computedFieldValueProvider (string, optional)β
Provider/class that computes the field value.
Applies to: computed
Default: N/A
computedFieldValueProviderCtxt (string, optional)β
Context/config passed to the computed value provider.
Applies to: computed
Default: N/A
computedFieldValueType (enum, optional)β
Declared output type of the computed field.
Applies to: computed
Values:
- string
- int
- decimal
- boolean
- date
- datetime
Default: string
computedFieldTriggerConfig (array of objects, optional)β
Operations that trigger compute and the trigger model/module to attach to. This is useful when the computed field depends on relations or other models and needs to be re-computed when those models change.
Config schema
export class ComputedFieldTriggerConfig {
moduleName: string; // Name of the module which should trigger the computed field re-evaluation
modelName: string; // Name of the model which should trigger the computed field re-evaluation
operations: ComputedFieldTriggerOperation[]; // List of operations on the model, when computed field should be re-evaluated
}
Operations values:
- before-insert
- after-insert
- before-update
- after-update
- before-delete
- after-delete
Applies to: computed
Default: N/A
isSystem (boolean, optional)β
System fields are excluded from code generation (hand-written code assumed).
Default: false
isMarkedForRemoval (boolean, optional)β
Soft-removal flag for the field definition. Fields marked for removal are excluded from code generation. Default: false
Info
This flag enables the code builder to identify fields that need to be deleted from the codebase. They are deleted after code generation is complete.
columnName (string, optional)β
Override database column name.
Default: Derived from name
relationCoModelColumnName (string, optional)β
Override co-model's column name for relation bindings.
Applies to: relation
Default: Auto-generated/inferred
isUserKey (boolean, optional)β
Marks this field as the user key (friendly identifier).
Further Reference:
Default: false
relationJoinTableName (string, optional)β
Custom join table name for many-to-many.
Applies to: relation (many-to-many)
Default: Auto-generated
enableAuditTracking (boolean, optional)β
Track create/update/delete for this field in audit logs.
Default: false
isMultiSelect (boolean, optional)β
Allow multiple selected values (UI + storage impact).
Applies to: selection fields and some primitives depending on UI policy
Default: false
Implementation Notes & Gotchasβ
ormTypevstypeβ Prefer defaults derived fromtype. OverrideormTypeonly when you need a specific DB type (e.g.,jsonbinstead ofjson).unique+indexβuniqueusually implies an index; still setindex: truefor frequent filter columns that arenβt unique.
- User key β Set
isUserKey: trueon the one field that identifies a record best for humans (e.g.,instituteName). - Selection fields β Ensure storage matches UI: arrays for multi-select; validate that
selectionValueTypealigns with downstream consumers. - Relations β Always specify
relationCascadeexplicitly; implicit defaults differ across ORMs/DBs. For many-to-many, define the owner side to control join-table updates. - Computed β Providers should be idempotent and sideβeffect free. For pre-compute operations e.g (before-insert, before-update, before-delete), provider needs to set the value on the entity object directly i.e (since in pre-compute operations, the assumption is that the computed field entity and the triggering entity are the same). For post-compute operations e.g (after-insert, after-update, after-delete), provider needs to use the entity manager in the provider implementation to update the entity since in post-compute operations, the assumption is that the computed field entity and the triggering entity can be different.
- Media β Validate MIME and size server-side.
mediaTypesis an allowlist, not a guarantee of safety. Consider thumbnailing and antivirus for file uploads.
Cheat Sheetβ
βββββββββββββββββββββββββββββββββββββββ
β DATA TYPE? β
βββββββββββββββββββββββββββββββββββββββ€
β TEXT: β
β βββ Short (< 1000 chars) β shortText β
β βββ Long/Multi-line β longText β
β βββ Formatted/HTML β richText β
βββββββββββββββββββββββββββββββββββββββ€
β NUMBERS: β
β βββ Whole numbers β int β
β βββ Decimals β decimal β
βββββββββββββββββββββββββββββββββββββββ€
β CHOICES: β
β βββ Fixed options β selectionStatic β
β βββ Dynamic data β selectionDynamic β
βββββββββββββββββββββββββββββββββββββββ€
β RELATIONSHIPS: β
β βββ One-to-One β relation β
β βββ One-to-Many β relation β
β βββ Many-to-One β relation β
β βββ Many-to-Many β relation β
βββββββββββββββββββββββββββββββββββββββ€
β FILES: β
β βββ Single file β mediaSingle β
β βββ Multiple files β mediaMultiple β
βββββββββββββββββββββββββββββββββββββββ€
β CALCULATED: β
β βββ Auto-computed β computed β
βββββββββββββββββββββββββββββββββββββββ€
β SPECIAL: β
β βββ True/False β boolean β
β βββ Date only β date β
β βββ Date+Time β datetime β
β βββ Password β password β
β βββ Email β email β
β βββ Phone β phone β
β βββ Complex data β json β
βββββββββββββββββββββββββββββββββββββββ