Custom Fields

Custom Fields Guide

This guide explains how to use the custom fields feature in Stood, which allows teams to define additional fields for Account, Contact, Deal, and Activity entities.

Overview

The custom fields feature provides a flexible way to extend the data model without code changes. Each team can define their own custom fields by uploading a datamodel.json file to Firebase Storage.

How It Works

  1. Team-specific Configuration: Each team has its own datamodel.json file stored in Firebase Storage at {teamId}/datamodel.json

  2. Dynamic Loading: The app loads custom field definitions at startup and when switching teams

  3. NoSQL Storage: Custom field values are stored directly in the same Firestore collections as the main entity data

  4. Type Safety: Custom fields support various data types with validation

Supported Field Types

Configuration File Structure

The datamodel.json file follows this structure:

{
"account": {
"fieldKey": {
"name": "Display Name",
"type": "fieldType",
"required": false,
"defaultValue": "default",
"options": ["option1", "option2"],
"description": "Field description",
"maxLength": 100,
"minValue": 0,
"maxValue": 100
}
},
"contact": { ... },
"deal": { ... },
"activity": { ... }
}

Field Properties

Data Storage

Custom fields are stored in the same Firestore documents as the main entity data:

{
"name": "Acme Corp",
"description": "Software company",
"customFields": {
"industry": "Technology",
"annualRevenue": 1000000,
"isPublic": true
}
}

Team Management

Migration and Backwards Compatibility

Full JSON example

{
"account": {
"industry": {
"name": "Industry",
"type": "select",
"required": false,
"options": [
"Technology",
"Healthcare",
"Finance",
"Manufacturing",
"Retail",
"Education",
"Government",
"Non-profit",
"Other"
],
"description": "The industry sector this account belongs to"
},
"annualRevenue": {
"name": "Annual Revenue",
"type": "number",
"required": false,
"minValue": 0,
"description": "Annual revenue in USD"
},
"employeeCount": {
"name": "Employee Count",
"type": "number",
"required": false,
"minValue": 1,
"description": "Number of employees in the company"
},
"foundedYear": {
"name": "Founded Year",
"type": "number",
"required": false,
"minValue": 1800,
"maxValue": 2024,
"description": "Year the company was founded"
},
"isPublic": {
"name": "Public Company",
"type": "boolean",
"required": false,
"defaultValue": false,
"description": "Whether the company is publicly traded"
},
"notes": {
"name": "Internal Notes",
"type": "textarea",
"required": false,
"maxLength": 1000,
"description": "Internal notes about this account"
}
},
"contact": {
"jobTitle": {
"name": "Job Title",
"type": "text",
"required": false,
"maxLength": 100,
"description": "Professional job title"
},
"department": {
"name": "Department",
"type": "select",
"required": false,
"options": [
"Sales",
"Marketing",
"IT",
"Finance",
"HR",
"Operations",
"Executive",
"Other"
],
"description": "Department within the organization"
},
"seniority": {
"name": "Seniority Level",
"type": "select",
"required": false,
"options": [
"Entry Level",
"Mid Level",
"Senior Level",
"Manager",
"Director",
"VP",
"C-Level"
],
"description": "Seniority level of the contact"
},
"linkedinProfile": {
"name": "LinkedIn Profile",
"type": "url",
"required": false,
"description": "LinkedIn profile URL"
},
"preferredContactMethod": {
"name": "Preferred Contact Method",
"type": "select",
"required": false,
"options": [
"Email",
"Phone",
"LinkedIn",
"SMS",
"Other"
],
"description": "Preferred method of communication"
},
"timezone": {
"name": "Timezone",
"type": "text",
"required": false,
"defaultValue": "UTC",
"description": "Contact's timezone"
},
"lastContactDate": {
"name": "Last Contact Date",
"type": "date",
"required": false,
"description": "Date of last contact with this person"
}
},
"deal": {
"probability": {
"name": "Deal Probability",
"type": "number",
"required": false,
"minValue": 0,
"maxValue": 100,
"description": "Probability of closing this deal (0-100%)"
},
"competitor": {
"name": "Main Competitor",
"type": "text",
"required": false,
"maxLength": 100,
"description": "Primary competitor for this deal"
},
"decisionMaker": {
"name": "Decision Maker",
"type": "text",
"required": false,
"maxLength": 100,
"description": "Name of the key decision maker"
},
"budgetApproved": {
"name": "Budget Approved",
"type": "boolean",
"required": false,
"defaultValue": false,
"description": "Whether budget has been approved"
},
"timeline": {
"name": "Expected Timeline",
"type": "select",
"required": false,
"options": [
"This Quarter",
"Next Quarter",
"This Year",
"Next Year",
"Undecided"
],
"description": "Expected timeline for closing"
},
"source": {
"name": "Deal Source",
"type": "select",
"required": false,
"options": [
"Cold Outreach",
"Referral",
"Website",
"Trade Show",
"Social Media",
"Partner",
"Other"
],
"description": "How this deal was sourced"
},
"customNotes": {
"name": "Deal Notes",
"type": "textarea",
"required": false,
"maxLength": 2000,
"description": "Additional notes about this deal"
}
},
"activity": {
"priority": {
"name": "Priority",
"type": "select",
"required": false,
"options": [
"Low",
"Medium",
"High",
"Urgent"
],
"description": "Priority level of this activity"
},
"estimatedDuration": {
"name": "Estimated Duration (minutes)",
"type": "number",
"required": false,
"minValue": 1,
"maxValue": 480,
"description": "Estimated duration in minutes"
},
"followUpRequired": {
"name": "Follow-up Required",
"type": "boolean",
"required": false,
"defaultValue": false,
"description": "Whether a follow-up is needed"
},
"followUpDate": {
"name": "Follow-up Date",
"type": "date",
"required": false,
"description": "Date for follow-up if required"
},
"outcome": {
"name": "Activity Outcome",
"type": "select",
"required": false,
"options": [
"Successful",
"Needs Follow-up",
"Rescheduled",
"Cancelled",
"No Response"
],
"description": "Outcome of this activity"
},
"location": {
"name": "Location",
"type": "text",
"required": false,
"maxLength": 200,
"description": "Location where activity took place"
},
"attendees": {
"name": "Attendees",
"type": "textarea",
"required": false,
"maxLength": 500,
"description": "List of attendees or participants"
}
}
}

Contact - Stood CRM support & integration

Published with Nuclino