+
+
+
diff --git a/schema/metadata/app/metadata.json b/schema/metadata/app/metadata.json
index 860922c15b..fb2b8e0da2 100644
--- a/schema/metadata/app/metadata.json
+++ b/schema/metadata/app/metadata.json
@@ -14,7 +14,7 @@
{
"type": "array",
"items": {
- "type": "array"
+ "type": "string"
}
}
]
diff --git a/schema/metadata/app/orm.json b/schema/metadata/app/orm.json
new file mode 100644
index 0000000000..ecfcecc006
--- /dev/null
+++ b/schema/metadata/app/orm.json
@@ -0,0 +1,35 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/orm.json",
+ "title": "app/orm",
+ "description": "ORM definitions.",
+ "type": "object",
+ "properties": {
+ "platforms": {
+ "type": "object",
+ "description": "Platforms.",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A platform name.",
+ "properties": {
+ "queryComposerClassName": {
+ "type": "string",
+ "description": "A query composer. Should implement Espo\\ORM\\QueryComposer\\QueryComposer."
+ },
+ "pdoFactoryClassName": {
+ "type": "string",
+ "description": "A PDF factory. Should implement Espo\\ORM\\PDO\\PDOFactory."
+ },
+ "functionConverterClassNameMap": {
+ "type": "object",
+ "description": "Function converters. Should implement Espo\\ORM\\QueryComposer\\Part\\FunctionConverter.",
+ "additionalProperties": {
+ "description": "A function name. Only upper case letters and _ are allowed.",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/pdfEngines.json b/schema/metadata/app/pdfEngines.json
new file mode 100644
index 0000000000..c64c0d4451
--- /dev/null
+++ b/schema/metadata/app/pdfEngines.json
@@ -0,0 +1,39 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/pdfEngines.json",
+ "title": "app/pdfEngines",
+ "description": "PDF printing engines.",
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "description": "An engine name.",
+ "properties": {
+ "implementationClassNameMap": {
+ "type": "object",
+ "description": "Implementations.",
+ "properties": {
+ "entity": {
+ "type": "string",
+ "description": "An entity printer. Should implement Espo\\Tools\\Pdf\\EntityPrinter."
+ },
+ "collection": {
+ "type": "string",
+ "description": "An entity printer. Should implement Espo\\Tools\\Pdf\\CollectionPrinter."
+ }
+ }
+ },
+ "fontFaceList": {
+ "type": "array",
+ "description": "A list of fonts available for the engine.",
+ "items": {
+ "anyOf": [
+ {"const": "__APPEND__"},
+ {
+ "type": "string"
+ }
+ ]
+ }
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/popupNotifications.json b/schema/metadata/app/popupNotifications.json
new file mode 100644
index 0000000000..7435c21dad
--- /dev/null
+++ b/schema/metadata/app/popupNotifications.json
@@ -0,0 +1,45 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/popupNotifications.json",
+ "title": "app/popupNotifications",
+ "description": "Popup notifications.",
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A name.",
+ "properties": {
+ "grouped": {
+ "type": "boolean",
+ "description": "Grouped popup notifications are fetched with a single API request."
+ },
+ "providerClassName": {
+ "type": "string",
+ "description": "A provider class. Actual only if the `grouped` parameter is set to true. Should implement Espo\\Tools\\PopupNotification\\Provider."
+ },
+ "useWebSocket": {
+ "type": "boolean",
+ "description": "If the WebSocked is configured and the parameter is set to true, notifications won't be polled in the front-end (except once, when page is loaded)."
+ },
+ "disabled": {
+ "type": "boolean",
+ "description": "Disables."
+ },
+ "portalDisabled": {
+ "type": "boolean",
+ "description": "Disables in portals."
+ },
+ "view": {
+ "type": "string",
+ "description": "A frontend view for the popup notification."
+ },
+ "interval": {
+ "type": "integer",
+ "description": "A polling interval in seconds. Actual if `grouped` is false."
+ },
+ "url": {
+ "type": "string",
+ "description": "An API endpoint used for polling. Actual if `grouped` is false."
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/portalContainerServices.json b/schema/metadata/app/portalContainerServices.json
new file mode 100644
index 0000000000..4dceb3e482
--- /dev/null
+++ b/schema/metadata/app/portalContainerServices.json
@@ -0,0 +1,25 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/consoleCommands",
+ "$id": "https://www.espocrm.com/schema/metadata/app/portalContainerServices.json",
+ "title": "app/portalContainerServices",
+ "description": "Overriding of container services for portals. Provides the ability to define custom implementations for portals.",
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A service name.",
+ "properties": {
+ "className": {
+ "type": "string",
+ "description": "A service class."
+ },
+ "loaderClassName": {
+ "type": "string",
+ "description": "A service loader class. Should implement Espo\\Core\\Container\\Loader interface."
+ },
+ "settable": {
+ "type": "boolean",
+ "description": "Whether the service can be set to the container externally (with the `set` method)."
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/rebuild.json b/schema/metadata/app/rebuild.json
new file mode 100644
index 0000000000..eb33f5fe09
--- /dev/null
+++ b/schema/metadata/app/rebuild.json
@@ -0,0 +1,16 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/rebuild.json",
+ "title": "app/rebuild",
+ "description": "Rebuild definitions.",
+ "type": "object",
+ "properties": {
+ "actionClassNameList": {
+ "type": "array",
+ "description": "Array of class names. Actions being processed when the application is being rebuilt. Should implement Espo\\Core\\Rebuild\\RebuildAction.",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/recordId.json b/schema/metadata/app/recordId.json
new file mode 100644
index 0000000000..234f5b69f1
--- /dev/null
+++ b/schema/metadata/app/recordId.json
@@ -0,0 +1,32 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/recordId.json",
+ "title": "app/recordId",
+ "description": "Record ID definitions.",
+ "type": "object",
+ "properties": {
+ "type": {
+ "enum": [
+ "id",
+ "uuid4"
+ ],
+ "description": "A type of generated IDs."
+ },
+ "length": {
+ "type": "integer",
+ "description": "ID column length. By default, set to 17."
+ },
+ "dbType": {
+ "description": "An ID column data type. By default, set to string (equivalent to varchar in MySQL). Changing this parameter will change types of all ID columns once you run rebuild."
+ "anyOf": [
+ {"type": "string"},
+ {
+ "enum": [
+ "string",
+ "uuid"
+ ]
+ }
+ ]
+ }
+ }
+}
diff --git a/schema/metadata/app/regExpPatterns.json b/schema/metadata/app/regExpPatterns.json
new file mode 100644
index 0000000000..fcab92e5db
--- /dev/null
+++ b/schema/metadata/app/regExpPatterns.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/regExpPatterns.json",
+ "title": "app/regExpPatterns",
+ "description": "Predefined regular expression patterns. Predefined patterns can be used for field validation.",
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A pattern name.",
+ "properties": {
+ "pattern": {
+ "type": "string",
+ "description": "A regular expression pattern."
+ },
+ "isSystem": {
+ "type": "boolean",
+ "description": "If true, the pattern won't be available when defining a validation for a field."
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/relationships.json b/schema/metadata/app/relationships.json
new file mode 100644
index 0000000000..9d935b108e
--- /dev/null
+++ b/schema/metadata/app/relationships.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/relationships.json",
+ "title": "app/relationships",
+ "description": "Definitions of specific named relationships.",
+ "type": "object",
+ "additionalProperties": {
+ "description": "A relationship name.",
+ "type": "object",
+ "properties": {
+ "converterClassName": {
+ "type": "string",
+ "description": "A converter. Converts metadata link definitions to ORM definitions. Should implement Espo\\Core\\Utils\\Database\\Orm\\LinkConverter."
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/scheduledJobs.json b/schema/metadata/app/scheduledJobs.json
new file mode 100644
index 0000000000..210e4db20f
--- /dev/null
+++ b/schema/metadata/app/scheduledJobs.json
@@ -0,0 +1,33 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/scheduledJobs.json",
+ "title": "app/scheduledJobs",
+ "description": "Scheduled jobs definitions. Defined scheduled job will be available for the admin when creating a scheduled job.",
+ "type": "object",
+ "additionalProperties": {
+ "description": "A job name. Should start with the upper case letter.",
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "A name to be used for job records. Not important."
+ },
+ "isSystem": {
+ "type": "boolean",
+ "description": "Whether the job is system."
+ },
+ "scheduling": {
+ "type": "string",
+ "description": "A default scheduling in crontab notation."
+ },
+ "jobClassName": {
+ "type": "string",
+ "description": "A job implementation. Should implement either Espo\\Core\\Job\\Job|Espo\\Core\\Job or Espo\\Core\\Job\\Job|Espo\\Core\\JobDataLess interfaces. Usage of the former requires having the preparator."
+ },
+ "preparatorClassName": {
+ "type": "string",
+ "description": "A preparator. Optional. The preparator is called by the application. It serves for creating job records. E.g. for email checking, the preparator creates jobs for each email account. Should implement Espo\\Core\\Job\\Preparator."
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/select.json b/schema/metadata/app/select.json
new file mode 100644
index 0000000000..c4b8a56fe4
--- /dev/null
+++ b/schema/metadata/app/select.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/select.json",
+ "title": "app/select",
+ "description": "Select framework definitions.",
+ "type": "object",
+ "properties": {
+ "boolFilterClassNameMap": {
+ "type": "object",
+ "description": "Bool filters available for all entity types. Should implement Espo\\Core\\Select\\Bool\\Filter.",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "orderItemConverterClassNameMap": {
+ "type": "object",
+ "description": "Order item converters for field types. Should implement Espo\\Core\\Select\\Order\\ItemConverter.",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "whereItemConverterClassNameMap": {
+ "type": "object",
+ "description": "Where item converters. Should implement Espo\\Core\\Select\\Where\\ItemConverter.",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/smsProviders.json b/schema/metadata/app/smsProviders.json
new file mode 100644
index 0000000000..fbbcc5603b
--- /dev/null
+++ b/schema/metadata/app/smsProviders.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/smsProviders.json",
+ "title": "app/smsProviders",
+ "description": "SMS providers.",
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A provider name.",
+ "properties": {
+ "senderClassName": {
+ "type": "string",
+ "description": "A sender class. Should implement Espo\\Core\\Sms\\Sender."
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/templateHelpers.json b/schema/metadata/app/templateHelpers.json
new file mode 100644
index 0000000000..30af6188f1
--- /dev/null
+++ b/schema/metadata/app/templateHelpers.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/templateHelpers.json",
+ "title": "app/templateHelpers",
+ "description": "Template helpers for the back-end templating system (used for PDF printing, email templates).",
+ "type": "object",
+ "additionalProperties": {
+ "type": "string",
+ "description": "A helper name and its implementation. Should implement Espo\\Core\\Htmlizer\\Helper."
+ }
+}
diff --git a/schema/metadata/app/templates.json b/schema/metadata/app/templates.json
new file mode 100644
index 0000000000..f5949fc6a7
--- /dev/null
+++ b/schema/metadata/app/templates.json
@@ -0,0 +1,35 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/smsProviders.json",
+ "title": "app/smsProviders",
+ "description": "Templates (available at Administration > Templates). Usually used for system emails.",
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A template name. Should start with the lower case letter.",
+ "properties": {
+ "scopeList": {
+ "type": "array",
+ "description": "A list of scopes (entity types) for which the template is available.",
+ "items": {
+ "anyOf": [
+ {"const": "__APPEND__"},
+ {"type": "string"}
+ ]
+ }
+ },
+ "scope": {
+ "type": "string",
+ "description": "A scope (entity types) for which the template is available. Use it if it's needed only for one entity type."
+ },
+ "scopeListConfigParam": {
+ "type": "string",
+ "description": "A config parameter defining for which entity types the template is available."
+ },
+ "module": {
+ "type": "string",
+ "description": "A module name."
+ }
+ }
+ }
+}
diff --git a/schema/metadata/app/webSocket.json b/schema/metadata/app/webSocket.json
new file mode 100644
index 0000000000..245cf0e386
--- /dev/null
+++ b/schema/metadata/app/webSocket.json
@@ -0,0 +1,44 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/app/webSocket.json",
+ "title": "app/webSocket",
+ "description": "WebSocket definitions.",
+ "type": "object",
+ "properties": {
+ "categories": {
+ "type": "object",
+ "description": "Categories. Define custom WebSocket events here. You can use dots in category names.",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A category.",
+ "properties": {
+ "paramList": {
+ "type": "array",
+ "items": {"type": "string"},
+ "description": "Parameters passed within a topic. E.g. the topic name myGroupName.myCustomName.Account.someId. This makes a topic name unique for a specific record. For global events, omit this parameter."
+ },
+ "accessCheckCommand": {
+ "type": "string",
+ "description": "A console command that will be used to check whether a topic is allowed for a user when they attempting to subscribe. Patameter placeholders starts with the colon :. The userId parameter contains a user ID. If access checking is not needed, omit this parameter."
+ }
+ }
+ }
+ },
+ "messagers": {
+ "type": "object",
+ "description": "Provides the ability to implement other messagers rather than the default ZeroMQ. E.g. RabbitMQ.",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A messager.",
+ "properties": {
+ "senderClassName": {
+ "description": "A sender. Should implement Espo\\Core\\WebSocket\\Sender."
+ },
+ "subscriberClassName": {
+ "description": "A subscriber. Should implement Espo\\Core\\WebSocket\\Subscriber."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/schema/metadata/authenticationMethods.json b/schema/metadata/authenticationMethods.json
new file mode 100644
index 0000000000..088f74479f
--- /dev/null
+++ b/schema/metadata/authenticationMethods.json
@@ -0,0 +1,111 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/authenticationMethods.json",
+ "title": "authenticationMethods",
+ "description": "An authentication method.",
+ "type": "object",
+ "properties": {
+ "api": {
+ "type": "boolean",
+ "description": "Defines that the method is to be used for pure API request, not from the front-end."
+ },
+ "credentialsHeader": {
+ "type": "string",
+ "description": "A header that is supposed to contain credentials. Actual only for API methods."
+ },
+ "login": {
+ "type": "object",
+ "description": "A framework providing the ability to call custom code on Sign-In button click on the login page.",
+ "properties": {
+ "handler": {
+ "type": "string",
+ "description": "A front-end class (should extend the abstract class handlers/login)."
+ },
+ "fallback": {
+ "type": "boolean",
+ "description": "Defines that a regular username/password login method is also available on the login page."
+ },
+ "fallbackConfigParam": {
+ "type": "string",
+ "description": "A config parameter name to be used to check whether fallback login is allowed."
+ },
+ "portal": {
+ "type": "boolean",
+ "description": "Whether the handler will be available for portals, (bool)."
+ },
+ "portalConfigParam": {
+ "type": "string",
+ "description": "A config parameter name to be used to check whether the handler will be available for portals."
+ },
+ "data": {
+ "type": "object",
+ "additionalProperties": true,
+ "description": "Arbitrary data to be passed to the handler. Can be actual as application metadata is not yet available on the login page."
+ }
+ }
+ },
+ "portalDefault": {
+ "type": "boolean",
+ "description": "If true, the method will be applied for portals when the method is selected as the default in the settings and the portal does not have a specific authentication provider."
+ },
+ "settings": {
+ "type": "object",
+ "description": "Defines config parameters and a form on the admin UI.",
+ "properties": {
+ "isAvailable": {
+ "type": "boolean",
+ "description": "Whether the method is available in the settings."
+ },
+ "layout": {
+ "description": "A layout.",
+ "$ref": "./../layouts/detail.json#/definitions/panel"
+ },
+ "fieldList": {
+ "description": "Settings fields.",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "dynamicLogic": {
+ "type": "object",
+ "description": "Dynamic logic.",
+ "properties": {
+ "fields": {
+ "type": "object",
+ "description": "Fields.",
+ "additionalProperties": {
+ "type": "object",
+ "description": "A field.",
+ "properties": {
+ "visible": {
+ "description": "Conditions making the field visible.",
+ "$ref": "./clientDefs.json#/definitions/dynamicLogicVisible"
+ },
+ "required": {
+ "$ref": "./clientDefs.json#/definitions/dynamicLogicRequired"
+ },
+ "readOnly": {
+ "$ref": "./clientDefs.json#/definitions/dynamicLogicReadOnly"
+ },
+ "invalid": {
+ "$ref": "./clientDefs.json#/definitions/dynamicLogicInvalid"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "provider": {
+ "type": "object",
+ "properties": {
+ "isAvailable": {
+ "type": "boolean",
+ "description": "Whether is available in the Authentication Provider entity."
+ }
+ }
+ }
+ }
+}
diff --git a/schema/metadata/entityDefs.json b/schema/metadata/entityDefs.json
index 5b04635980..03f9fab0bb 100644
--- a/schema/metadata/entityDefs.json
+++ b/schema/metadata/entityDefs.json
@@ -16,96 +16,7 @@
"description": "Links.",
"type": "object",
"additionalProperties": {
- "type": "object",
- "description": "A link.",
- "additionalProperties": true,
- "properties": {
- "type": {
- "type": "string",
- "description": "A link type.",
- "enum": ["belongsTo", "hasMany", "hasOne", "belongsToParent", "hasChildren"]
- },
- "entity": {
- "type": "string",
- "description": "A foreign entity type."
- },
- "foreign": {
- "type": "string",
- "description": "A foreign link name."
- },
- "noJoin": {
- "type": "boolean",
- "description": "Prevents joining a foreign table when fetching a record. Available for belongsTo, hasOne."
- },
- "foreignName": {
- "type": "string",
- "description": "A field to be used as a name of a foreign record. Needed when a foreign entity type does not have the field name."
- },
- "audited": {
- "type": "boolean",
- "description": "Linking and unlinking will be logged in the Stream. Available for hasMany."
- },
- "layoutRelationshipsDisabled": {
- "type": "boolean",
- "description": "Makes the link not available in the Bottom Panels layout (in the Layout Manager tool). Available for hasMany"
- },
- "relationName": {
- "type": "string",
- "description": "A relationship name. Defines how a middle table will be named (for a many-to-many relationships). Available for hasMany"
- },
- "additionalColumns": {
- "type": "object",
- "description": "Additional columns to be created in a middle table (for a many-to-many relationships).",
- "additionalProperties": {
- "type": "object",
- "properties": {
- "type": {
- "enum": ["varchar", "int", "float", "bool"]
- },
- "maxLength": {
- "type": "integer"
- },
- "default": {
- "type": ["integer", "string", "boolean", "null", "number"]
- },
- "dbType": {
- "type": "string"
- }
- }
- }
- },
- "conditions": {
- "type": "object",
- "description": "Where-conditions (for a many-to-many relationships). If multiple links share the same relationship name (middle table), conditions must be defined for each link. For many-to-many.",
- "additionalProperties": {
- "type": ["string", "integer", "number", "boolean", "null"]
- }
- },
- "indexes": {
- "type": "object",
- "description": "Indexes for a middle table.",
- "additionalProperties": {
- "type": "object",
- "properties": {
- "columns": {
- "type": "array",
- "items": {
- "type": "string"
- },
- "description": "Database columns of the index."
- },
- "unique": {
- "type": "boolean",
- "description": "Whether the index is unique."
- }
- }
- }
- },
- "notMergeable": {
- "type": "boolean",
- "description": "Disable merging related records when duplicate records are being merged. For hasMany, hasChildren."
- }
- }
+ "$ref": "#/definitions/linkDefs"
}
},
"indexes": {
@@ -646,6 +557,98 @@
}
}
}
+ },
+ "linkDefs": {
+ "type": "object",
+ "description": "A link.",
+ "additionalProperties": true,
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A link type.",
+ "enum": ["belongsTo", "hasMany", "hasOne", "belongsToParent", "hasChildren"]
+ },
+ "entity": {
+ "type": "string",
+ "description": "A foreign entity type."
+ },
+ "foreign": {
+ "type": "string",
+ "description": "A foreign link name."
+ },
+ "noJoin": {
+ "type": "boolean",
+ "description": "Prevents joining a foreign table when fetching a record. Available for belongsTo, hasOne."
+ },
+ "foreignName": {
+ "type": "string",
+ "description": "A field to be used as a name of a foreign record. Needed when a foreign entity type does not have the field name."
+ },
+ "audited": {
+ "type": "boolean",
+ "description": "Linking and unlinking will be logged in the Stream. Available for hasMany."
+ },
+ "layoutRelationshipsDisabled": {
+ "type": "boolean",
+ "description": "Makes the link not available in the Bottom Panels layout (in the Layout Manager tool). Available for hasMany"
+ },
+ "relationName": {
+ "type": "string",
+ "description": "A relationship name. Defines how a middle table will be named (for a many-to-many relationships). Available for hasMany"
+ },
+ "additionalColumns": {
+ "type": "object",
+ "description": "Additional columns to be created in a middle table (for a many-to-many relationships).",
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "enum": ["varchar", "int", "float", "bool"]
+ },
+ "maxLength": {
+ "type": "integer"
+ },
+ "default": {
+ "type": ["integer", "string", "boolean", "null", "number"]
+ },
+ "dbType": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "conditions": {
+ "type": "object",
+ "description": "Where-conditions (for a many-to-many relationships). If multiple links share the same relationship name (middle table), conditions must be defined for each link. For many-to-many.",
+ "additionalProperties": {
+ "type": ["string", "integer", "number", "boolean", "null"]
+ }
+ },
+ "indexes": {
+ "type": "object",
+ "description": "Indexes for a middle table.",
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "columns": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Database columns of the index."
+ },
+ "unique": {
+ "type": "boolean",
+ "description": "Whether the index is unique."
+ }
+ }
+ }
+ },
+ "notMergeable": {
+ "type": "boolean",
+ "description": "Disable merging related records when duplicate records are being merged. For hasMany, hasChildren."
+ }
+ }
}
}
}
diff --git a/schema/metadata/fields.json b/schema/metadata/fields.json
new file mode 100644
index 0000000000..7c4838fd35
--- /dev/null
+++ b/schema/metadata/fields.json
@@ -0,0 +1,164 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://www.espocrm.com/schema/metadata/fields.json",
+ "title": "fields",
+ "description": "Field definitions.",
+ "type": "object",
+ "properties": {
+ "notMergeable": {
+ "type": "boolean",
+ "description": "Whether this field type is mergeable (when merging duplicate records)."
+ },
+ "notCreatable": {
+ "type": "boolean",
+ "description": "Whether the field of this type can be created in the Entity Manager tool."
+ },
+ "readOnly": {
+ "type": "boolean",
+ "description": "Is this field type Read Only (can't be edited)."
+ },
+ "skipOrmDefs": {
+ "type": "boolean",
+ "description": "Skip converting to defs for the ORM."
+ },
+ "filter": {
+ "type": "boolean",
+ "description": "Records can be filtered by this field (available as filter on the list view)."
+ },
+ "view": {
+ "type": "string",
+ "description": "A frontend view."
+ },
+ "params": {
+ "type": "array",
+ "description": "Field parameters.",
+ "items": {
+ "allOf": [
+ {
+ "$ref": "./entityDefs.json#/definitions/fieldDefs"
+ },
+ {
+ "properties": {
+ "hidden": {
+ "type": "boolean",
+ "description": "Do not display the parameter in the field manager."
+ },
+ "name": {
+ "type": "string",
+ "description": "A name."
+ }
+ }
+ }
+ ]
+ }
+ },
+ "fieldDefs": {
+ "description": "An object of field type definition",
+ "$ref": "./entityDefs.json#/definitions/fieldDefs"
+ },
+ "translatedOptions": {
+ "type": "boolean",
+ "description": "Does the field have options that can be translated."
+ },
+ "hookClassName": {
+ "type": "string",
+ "description": "A hook class. Called after the field is created or edited in the Entity Manager tool."
+ },
+ "fields": {
+ "type": "object",
+ "description": "Definitions of additional fields that will be created with this field. E.g. for address field, separate fields (street, city, etc.) are created.",
+ "additionalProperties": {
+ "$ref": "./entityDefs.json#/definitions/fieldDefs"
+ }
+ },
+ "naming": {
+ "enum": ["suffix", "prefix"],
+ "description": "The naming determines how additional fields will be named."
+ },
+ "actualFields": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "The list of actual attributes (which contain useful data). For example, for field type link in actualFields is ['id'], in notActualFields is ['name']. Means, if you load record with link field, you have values in {fieldName}Id and {fieldName}Name (suffix naming). But you need set only {fieldName}Id, if you want to update this field."
+ },
+ "notActualFields": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "The list of not actual attributes."
+ },
+ "personalData": {
+ "type": "boolean",
+ "description": "Where the field may contain personal data."
+ },
+ "textFilter": {
+ "type": "boolean",
+ "description": "The field will be available in the list of text filters (in the Entity Manager tool)."
+ },
+ "textFilterForeign": {
+ "type": "boolean",
+ "description": "The field will be available in the list of text filters as a foreign field."
+ },
+ "linkDefs": {
+ "$ref": "./entityDefs.json#/definitions/linkDefs",
+ "description": "If defined, a link with the same name as the field name will be created."
+ },
+ "fullTextSearch": {
+ "type": "boolean",
+ "description": "Full-text search will be available for the field."
+ },
+ "fullTextSearchColumnList": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Columns used in full-text search."
+ },
+ "valueFactoryClassName": {
+ "type": "string",
+ "description": "A factory that creates value-objects for this field. A value-object can be obtained by calling getValueObject method on an Entity. Should implement Espo\\ORM\\Value\\ValueFactory."
+ },
+ "attributeExtractorClassName": {
+ "type": "string",
+ "description": "A class that extracts values (attribute => value map) from a value-object. Used internally for obtaining values from a value-object and writing them to an entity. Should implement Espo\\ORM\\Value\\AttributeExtractor."
+ },
+ "validationList": {
+ "type": "array",
+ "items": {
+ "anyOf": [
+ {"type": "string"},
+ {"const": "__APPEND__"}
+ ]
+ },
+ "description": "Validations applied server-side."
+ },
+ "mandatoryValidationList": {
+ "type": "array",
+ "items": {
+ "anyOf": [
+ {"type": "string"},
+ {"const": "__APPEND__"}
+ ]
+ },
+ "description": "Validations applied server-side."
+ },
+ "validatorClassNameMap": {
+ "type": "object",
+ "description": "Validators. Should implement Espo\\Core\\FieldValidation\\Validator.",
+ "additionalProperties": {
+ "type": "string",
+ "description": "A validation name."
+ }
+ },
+ "duplicatorClassName": {
+ "type": "string",
+ "description": "Duplicates attributes of a field. Some fields can require some processing when an entity is being duplicated. Should implement Espo\\Core\\Record\\Duplicator\\FieldDuplicator."
+ },
+ "converterClassName": {
+ "type": "string",
+ "description": "A metadata converter. Converts field metadata to ORM metadata. Should implement Espo\\Core\\Utils\\Database\\Orm\\FieldConverter."
+ }
+ }
+}