HotCRM Logo

Seed Data Guide

How to create, manage, and validate seed data in HotCRM packages.

Seed Data Guide

HotCRM uses seed data to populate the database with initial reference data and sample records for development, testing, and demo environments. Each package can define its own seed files that are loaded in dependency order.

Overview

MetricValue
Total Seed Files39 across 14 packages
Total Dataset Files43 across 14 packages
Seed File Convention*.seed.ts (raw data arrays)
Dataset File Convention*.dataset.ts (DatasetSchema-compliant)
Loader Scriptscripts/seed.ts
Load StrategyDependency-ordered (topological sort)

DatasetSchema Protocol

All seed data is wrapped in DatasetSchema-compliant dataset files per the @objectstack/spec Data Seeding Protocol. Each dataset declares its target object, upsert key, conflict mode, and environment scope.

Dataset File Format

// packages/{package}/src/{entity}.dataset.ts
import { type DatasetInput, DatasetSchema } from '@objectstack/spec/data';
import { EntitySeedData } from './entity.seed.js';

export const EntityDataset: DatasetInput = {
  object: 'entity',           // Target object (snake_case)
  externalId: 'name',         // Idempotent upsert key
  mode: 'upsert',             // Conflict strategy
  env: ['prod', 'dev', 'test'], // Environment scope
  records: EntitySeedData,     // Data records from *.seed.ts
};

DatasetSchema.parse(EntityDataset);

export default EntityDataset;

DatasetSchema Fields

FieldTypeDefaultDescription
objectstring(required)Target object name (snake_case)
externalIdstring'name'Field used as upsert key for idempotent loading
mode'upsert' | 'insert' | 'ignore' | 'replace' | 'update''upsert'Conflict resolution strategy
env('prod' | 'dev' | 'test')[]['prod', 'dev', 'test']Which environments to load this data in
recordsRecord<string, unknown>[](required)Array of data records

Environment & Mode Strategy

Data TypeModeEnvironmentExample
Reference data (currencies, countries, industries)upsert['prod', 'dev', 'test']currency.dataset.ts
Demo/sample business data (accounts, leads)ignore['dev', 'test']account.dataset.ts
  • Reference data uses upsert to ensure it's always current, in all environments.
  • Demo data uses ignore to avoid overwriting production data, and is excluded from prod.

File Naming Convention

Seed files and dataset files follow the standard HotCRM naming convention:

packages/{package}/src/{entity}.seed.ts      ← Raw data arrays
packages/{package}/src/{entity}.dataset.ts   ← DatasetSchema wrapper

Examples:

  • packages/crm/src/account.seed.ts — Account sample data (raw array)
  • packages/crm/src/account.dataset.ts — Account dataset (DatasetSchema-compliant)
  • packages/core/src/system.seed.ts — System-level reference data
  • packages/core/src/currency.dataset.ts — Currency dataset

Writing Seed & Dataset Files

Step 1: Create the Seed File (Raw Data)

Each seed file exports a named array of plain objects representing database records:

/**
 * Account Seed Data
 * Sample accounts representing a mix of industries and sizes
 */
export const AccountSeedData = [
  {
    name: 'Acme Corporation',
    industry: 'Technology',
    type: 'Customer',
    annual_revenue: 5000000,
    employees: 250,
    status: 'active',
  },
  {
    name: 'GlobalTech Solutions',
    industry: 'Technology',
    type: 'Customer',
    annual_revenue: 12000000,
    employees: 800,
    status: 'active',
  },
];

export default AccountSeedData;

Step 2: Create the Dataset File (DatasetSchema Wrapper)

Wrap the seed data in a DatasetSchema-compliant dataset:

import { type DatasetInput, DatasetSchema } from '@objectstack/spec/data';
import { AccountSeedData } from './account.seed.js';

export const AccountDataset: DatasetInput = {
  object: 'account',
  externalId: 'name',
  mode: 'ignore',              // Demo data — don't overwrite
  env: ['dev', 'test'],        // Not loaded in production
  records: AccountSeedData,
};

DatasetSchema.parse(AccountDataset);

export default AccountDataset;

Step 3: Register in Plugin

Add the dataset to the plugin's data field:

import { AccountDataset } from './account.dataset.js';

export const CRMPlugin = {
  // ...other fields...
  data: [
    AccountDataset,
    // ...other datasets...
  ],
};

Best Practices

  • Export both named and default: Always export both export const EntitySeedData and export default.
  • Include realistic data: Use realistic names, amounts, and dates for demo environments.
  • Cover edge cases: Include records in different statuses (active, inactive, draft, etc.).
  • Use consistent types: Match field types to the corresponding *.object.ts definition.
  • Minimum 3-5 records: Each seed file should have enough data for meaningful testing.

Package Load Order

Seed data is loaded in dependency order to ensure referential integrity. The load order is defined in scripts/seed.ts:

OrderPackageDependencies
1core
2crmcore
3financecore, crm
4productscore
5hrcore
6supportcore, crm
7marketingcore, crm
8analyticscore
9integrationcore
10communitycore
11healthcarecore, crm
12financial-servicescore, crm, finance
13real-estatecore, crm
14educationcore

Seed Files by Package

PackageSeed Files
Coresystem.seed.ts
CRMaccount, contact, lead, opportunity, industry
Financecurrency, invoice, payment
Productsproduct, price_book
HRemployee, department, job_posting
Supportcase, kb_article
Marketingcampaign, campaign_type, email_template
Analyticsreport
Integrationconnection
Communityidea, topic
Healthcarepatient, appointment, insurance, prescription
Financial Serviceswealth_account, portfolio, advisory, kyc
Real Estateproperty, listing, showing, real_estate_offer
Educationcourse, student, enrollment, scholarship

Validation

HotCRM provides a seed data validation utility in packages/core/src/seed_validation.ts:

import { validateSeedData } from '@hotcrm/core/seed_validation';

const result = validateSeedData(AccountSeedData, {
  minRecords: 5,
  requiredFields: ['name', 'industry', 'status'],
  strictRequired: true,
});

console.log(result.valid);       // true
console.log(result.recordCount); // 10
console.log(result.errors);      // []

Running the Seed Loader

# Load all seed data for dev environment (default)
npx ts-node scripts/seed.ts

# Load seed data for production (only reference data)
npx ts-node scripts/seed.ts --prod

# Load seed data for test environment
npx ts-node scripts/seed.ts --test

# Reset and reload all seed data
npx ts-node scripts/seed.ts --reset

Adding Seed Data to a New Package

  1. Create the seed file: packages/{pkg}/src/{entity}.seed.ts
  2. Create the dataset file: packages/{pkg}/src/{entity}.dataset.ts
  3. Register the dataset in the plugin's data field in packages/{pkg}/src/plugin.ts
  4. Add the package to packages/core/src/dependency_graph.ts
  5. Write validation tests in packages/core/__tests__/unit/seeds/

On this page