Ivandt logo

Schema

Complete reference for IvtSchema configuration

The schema (IvtSchema) is the core configuration object that defines your import flow. It specifies fields, validation rules, transformers, and behavior for each step of the import process.

Basic Structure

import type { IvtSchema } from '@ivandt/importer';

const schema: IvtSchema = {
  // Required
  title: 'Product Import',
  key: 'unique-schema-key',
  publicKey: 'pk_live_xxx',
  sessionToken: 'session_xxx',
  fields: [
    // Field definitions
  ],

  // Optional
  id: 'template-uuid',
  dataSources: {},
  stepsConfig: {},
  advanced: {},
  eventHandlers: {},
  environment: 'prod',
  initialData: [],
  initialFile: null
};

Required Properties

title

The title is stored for tracking and auditing. When you view your imports in the dashboard, the title helps you understand each schema's purpose.

  • Type: string
  • Required: Yes
{
  title: 'Customer Import'
}

key

A unique string identifier for this schema. When id is not provided, the server uses key to create and store the schema on first submission. Further imports refer to the generated id.

  • Type: string
  • Required: No
  • Default: 'default-schema-key'
{
  key: 'product-import-v1'
}

publicKey

Your Ivandt public key (pk_live_xxx). Safe to expose in frontend code, restricted by allowed origins.

To get a public key, log into Ivandt and go to /dashboard/environments. You can create as many environments as you need.

  • Type: string
  • Required: Yes
{
  publicKey: 'pk_live_abc123...'
}

sessionToken

A short-lived session token generated from your backend using your secret key. Valid for 1 hour by default (max 1 day).

See Getting Started for how to create session tokens.

  • Type: string
  • Required: Yes
{
  sessionToken: 'eyJhbGc...'
}

fields

The fields are at the core of the importer. Each field defines a column with its own UI component, validators, and transformers.

{
  fields: [
    {
      type: 'text',
      label: 'Product Name',
      key: 'name',
      order: 0
    },
    {
      type: 'numeric',
      label: 'Price',
      key: 'price',
      order: 1
    }
  ]
}

Optional Properties

id

A unique UUID for this schema. If provided, the server assumes the schema is already created and saved to templates on ivandt.com.

Schemas are stored on our server because all imports are correlated to the template for tracking and auditing.

  • Type: string
  • Required: No
  • Default: Auto-generated UUID
{
  id: '550e8400-e29b-41d4-a716-446655440000'
}

dataSources

JavaScript objects that can be queried at runtime by dropdown fields. DataSources enable dynamic, dependent dropdowns without manual event handling.

  • Type: Record<string, any>
  • Required: No
  • Default: {}
  • See: DataSources
{
  dataSources: {
    countries: [
      { name: 'Australia', code: 'AU', states: [...] },
      { name: 'United States', code: 'US', states: [...] }
    ]
  }
}

environment

Useful for tracking and auditing. When provided, you can later query data for that specific environment.

  • Type: 'local' | 'dev' | 'staging' | 'prod'
  • Required: No
  • Default: 'local'
{
  environment: 'prod'
}

initialData

If you don't need the importer to parse a file and only need the Review step for validation and transformation, populate this field.

When provided, the importer skips to the Review step since there's no parsing or mapping involved. Your initialData structure should be a flat list of rows matching your schema fields.

  • Type: Array<Record<string, IvtCellValue>>
  • Required: No
  • Default: undefined
{
  initialData: [
    { name: 'Product 1', price: 100 },
    { name: 'Product 2', price: 200 }
  ]
}

initialFile

Similar to initialData, but you're passing an actual file (Excel, CSV, etc.). The importer works as usual with the mapping step.

Useful when you're downloading a file from somewhere and passing it to the importer instead of letting users upload.

  • Type: File
  • Required: No
  • Default: undefined
{
  initialFile: downloadedFile
}

stepsConfig

Configuration for each step of the import process. All properties are optional with sensible defaults.

advanced

Advanced configuration for web worker behavior. You probably never need to override these.

eventHandlers

Lifecycle hooks for custom logic during the import process.

Steps Configuration

uploadFileStep

Configuration for the file upload step.

{
  stepsConfig: {
    uploadFileStep: {
      supportedExtensions: ['xlsx', 'xls', 'csv', 'json', 'txt'],
      maxColumns: 10,
      maxRows: 100000,
      maxFileSize: 20 * 1024 * 1024,  // 20MB
      dataEntryMethod: 'manual_and_upload'
    }
  }
}

supportedExtensions

List of file extensions the importer will accept.

  • Type: string[]
  • Default: ['xlsx', 'xls', 'json', 'csv', 'txt']

dataEntryMethod

How users can enter data:

  • 'manual' - Skip file upload, go straight to Review step

  • 'upload' - Require file upload

  • 'manual_and_upload' - Allow both manual entry and file upload

  • Type: 'manual' | 'upload' | 'manual_and_upload'

  • Default: 'manual_and_upload'

maxColumns

Maximum number of columns the uploaded file can have.

  • Type: number
  • Default: 10

maxRows

Maximum number of rows the uploaded file can have.

  • Type: number
  • Default: 100000

maxFileSize

Maximum file size in bytes.

  • Type: number
  • Default: 20971520 (20MB)

mapHeadersStep

Configuration for the column mapping step.

{
  stepsConfig: {
    mapHeadersStep: {
      passThroughExcessColumns: false,
      unMatchedHeadersBehaviour: 'block',
      intelligentImport: true
    }
  }
}

passThroughExcessColumns

If the uploaded file has more columns than the schema, should excess columns be included?

When true, excess columns have no validations or transformations but are shown in Review and included in final submission.

  • Type: boolean
  • Default: false

unMatchedHeadersBehaviour

What happens if there are unmapped columns:

  • 'block' - Prevent proceeding with unmapped columns

  • 'warn' - Allow proceeding but show warning

  • 'allow' - Allow proceeding without warning

  • Type: 'block' | 'allow' | 'warn'

  • Default: 'block'

intelligentImport

When enabled, the system attempts to automatically skip header selection and mapping steps when:

  • Excel file has only one sheet
  • Header row can be intelligently detected
  • All schema fields can be perfectly mapped to Excel headers

When disabled, users always go through all steps manually.

  • Type: boolean
  • Default: true

reviewStep

Configuration for the review and submission step.

{
  stepsConfig: {
    reviewStep: {
      invalidDataBehaviour: 'block_submit',
      storeInIvandtServer: true,
      allowCustomColumn: false,
      allowSubmitCancel: false,
      pagination: { pageSize: 500 }
    }
  }
}

invalidDataBehaviour

What happens when user submits with invalid rows:

  • 'block_submit' - Prevent submission

  • 'remove_invalid_rows' - Remove invalid rows and submit valid ones

  • 'include_invalid_rows' - Include everything

  • Type: 'block_submit' | 'remove_invalid_rows' | 'include_invalid_rows'

  • Default: 'block_submit'

storeInIvandtServer

Whether final data should be stored in Ivandt servers.

Even when false, we still store metadata (date, filename, row counts) for audit trailing. Only the actual data is not stored.

  • Type: boolean
  • Default: true

allowCustomColumn

If enabled, users can create extra columns in the Review step and submit them with their data.

  • Type: boolean
  • Default: false

allowSubmitCancel

If enabled, users can cancel submission and the onSubmitCancel event will be called.

  • Type: boolean
  • Default: false

pagination

If enabled, data is split into pages for easier navigation through large datasets.

  • Type: boolean | { pageSize: number }
  • Default: { pageSize: 500 }
// Disable pagination
pagination: false

// Custom page size
pagination: { pageSize: 1000 }

Advanced Configuration

You probably never need to override these. They control how web workers handle validation and transformation.

{
  advanced: {
    maxInMemoryValidationRows: 500,
    maxPerWorkerValidationRows: 10000,
    maxInMemoryTransformationRows: 500,
    maxPerWorkerTransformationRows: 10000
  }
}

maxInMemoryValidationRows

Maximum rows validated in memory before splitting to workers.

  • Type: number
  • Default: 500

maxPerWorkerValidationRows

Maximum rows each validation worker handles.

  • Type: number
  • Default: 10000

maxInMemoryTransformationRows

Maximum rows transformed in memory before splitting to workers.

  • Type: number
  • Default: 500

maxPerWorkerTransformationRows

Maximum rows each transformation worker handles.

  • Type: number
  • Default: 10000

Complete Example

import type { IvtSchema } from '@ivandt/importer';

const schema: IvtSchema = {
  // Required
  title: 'Product Import',
  key: 'product-import-v1',
  publicKey: 'pk_live_xxx',
  sessionToken: 'session_xxx',

  // Fields
  fields: [
    {
      type: 'text',
      label: 'Product Name',
      key: 'name',
      order: 0,
      validators: [{ type: 'required' }]
    },
    {
      type: 'numeric',
      label: 'Price',
      key: 'price',
      order: 1,
      validators: [
        { type: 'required' },
        { type: 'min', value: 0 }
      ]
    },
    {
      type: 'dropdown',
      label: 'Category',
      key: 'category',
      order: 2,
      options: [
        { label: 'Electronics', value: 'electronics' },
        { label: 'Clothing', value: 'clothing' }
      ]
    }
  ],

  // Optional
  environment: 'prod',

  // Steps configuration
  stepsConfig: {
    uploadFileStep: {
      maxFileSize: 50 * 1024 * 1024,  // 50MB
      maxRows: 500000
    },
    mapHeadersStep: {
      intelligentImport: true
    },
    reviewStep: {
      invalidDataBehaviour: 'remove_invalid_rows',
      pagination: { pageSize: 1000 }
    }
  },

  // Event handlers
  eventHandlers: {
    onSubmit: async (tableRows, meta, cellErrors, submitMeta) => {
      await fetch('/api/products/bulk', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ data: tableRows, meta })
      });
    }
  }
};