TGM Manager provides a powerful custom fields system that allows you to extend existing entities with additional fields without modifying the core schema. This enables organizations to capture industry-specific or business-specific data.

Overview

Custom fields are dynamic attributes that can be added to any entity type (e.g., Asset, WorkOrder, Component). Each custom field has:

  • Definition - Metadata about the field (type, validation rules, display settings)
  • Values - Actual data stored per entity instance

Field Types

Type Description Validation Options
STRING Short text (max 255 chars) minLength, maxLength, regex
TEXT Long text (unlimited) -
NUMBER Integer or decimal min, max
BOOLEAN True/false value -
DATE Date only (ISO 8601) -
DATETIME Date and time (ISO 8601) -
JSON JSON object or array -
ENUM Predefined list of values values (array)

REST API

Field Definitions

Get Available Types

GET /api/custom-field-definitions/types

Response:

["STRING", "TEXT", "NUMBER", "BOOLEAN", "DATE", "DATETIME", "JSON", "ENUM"]

List Fields for Entity Type

GET /api/custom-field-definitions/{entityType}

Parameters: - entityType - The entity type (e.g., "Asset", "WorkOrder") - activeOnly (optional) - Filter by active status (default: true)

Response:

[
  {
    "id": 1,
    "entityType": "Asset",
    "fieldName": "serialNumber",
    "fieldType": "STRING",
    "displayName": "Serial Number",
    "description": "Manufacturer serial number",
    "isRequired": true,
    "defaultValue": null,
    "validationRules": {
      "minLength": 5,
      "maxLength": 50,
      "regex": "^[A-Z0-9-]+$"
    },
    "isActive": true,
    "displayOrder": 1,
    "helpText": "Enter the manufacturer serial number",
    "placeholder": "e.g., SN-12345-ABC"
  }
]

Get Specific Field

GET /api/custom-field-definitions/{entityType}/{fieldName}

Create Custom Field

POST /api/custom-field-definitions
Content-Type: application/json

{
  "entityType": "Asset",
  "fieldName": "warrantyExpiry",
  "fieldType": "DATE",
  "displayName": "Warranty Expiry",
  "description": "Date when warranty expires",
  "isRequired": false,
  "defaultValue": null,
  "validationRules": null,
  "isActive": true,
  "displayOrder": 2,
  "helpText": "Enter the warranty expiration date",
  "placeholder": "YYYY-MM-DD"
}

Update Custom Field

PUT /api/custom-field-definitions/{id}
Content-Type: application/json

{
  "entityType": "Asset",
  "fieldName": "warrantyExpiry",
  "fieldType": "DATE",
  "displayName": "Warranty Expiration Date",
  "isRequired": true,
  "displayOrder": 1
}

Toggle Active Status

PATCH /api/custom-field-definitions/{id}/toggle

Check Existing Data

Before deleting a field, check if any entities have data for it:

GET /api/custom-field-definitions/{id}/check-data

Response:

{
  "fieldId": 1,
  "entityType": "Asset",
  "fieldName": "serialNumber",
  "entitiesWithData": 42,
  "warning": "Deleting this field will orphan data in 42 entities. Use cleanupData=true to remove the data."
}

Delete Custom Field

DELETE /api/custom-field-definitions/{id}?cleanupData=false

Parameters: - cleanupData (optional) - If true, removes field values from all entities (default: false)

Validation Rules

Validation rules are stored as JSON and vary by field type:

STRING Fields

{
  "minLength": 5,
  "maxLength": 100,
  "regex": "^[A-Z].*"
}

NUMBER Fields

{
  "min": 0,
  "max": 1000
}

ENUM Fields

{
  "values": ["Low", "Medium", "High", "Critical"]
}

Usage Examples

Creating a Priority Field

curl -X POST http://localhost:1337/api/custom-field-definitions \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "WorkOrder",
    "fieldName": "priority",
    "fieldType": "ENUM",
    "displayName": "Priority",
    "description": "Work order priority level",
    "isRequired": true,
    "defaultValue": "Medium",
    "validationRules": {
      "values": ["Low", "Medium", "High", "Critical"]
    },
    "displayOrder": 1
  }'

Creating a Cost Estimate Field

curl -X POST http://localhost:1337/api/custom-field-definitions \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "WorkOrder",
    "fieldName": "estimatedCost",
    "fieldType": "NUMBER",
    "displayName": "Estimated Cost",
    "description": "Estimated cost in dollars",
    "isRequired": false,
    "validationRules": {
      "min": 0,
      "max": 1000000
    },
    "displayOrder": 2,
    "placeholder": "0.00"
  }'

Creating a JSON Metadata Field

curl -X POST http://localhost:1337/api/custom-field-definitions \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "Asset",
    "fieldName": "specifications",
    "fieldType": "JSON",
    "displayName": "Technical Specifications",
    "description": "Detailed technical specifications as JSON",
    "isRequired": false,
    "helpText": "Enter specifications as key-value pairs"
  }'

Integration with Entities

Custom field values are stored in the customFields JSONB column of each entity. When saving an entity, include custom fields in the request:

{
  "name": "Pump A-101",
  "type": "PUMP",
  "customFields": {
    "serialNumber": "SN-12345-ABC",
    "warrantyExpiry": "2025-12-31",
    "specifications": {
      "flowRate": "100 GPM",
      "pressure": "150 PSI"
    }
  }
}

Best Practices

  1. Use meaningful field names - Use camelCase and be descriptive (e.g., warrantyExpiryDate not wd)

  2. Set appropriate validation - Always add validation rules to ensure data quality

  3. Order fields logically - Use displayOrder to group related fields together

  4. Provide help text - Add helpText and placeholder to guide users

  5. Test before production - Use the check-data endpoint before deleting fields

  6. Consider required fields - Only mark fields as required if truly necessary

Error Handling

Error Status Description
Field already exists 409 Conflict A field with this name already exists for the entity type
Validation failed 400 Bad Request The provided value doesn't match validation rules
Field not found 404 Not Found The specified field definition doesn't exist