vtex-io-masterdata

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

MasterData v2 Integration

MasterData v2 集成

When this skill applies

本技能的适用场景

Use this skill when your VTEX IO app needs to store custom data (reviews, wishlists, form submissions, configuration records), query or filter that data, or set up automated workflows triggered by data changes.
  • Defining data entities and JSON Schemas using the
    masterdata
    builder
  • Performing CRUD operations through MasterDataClient (
    ctx.clients.masterdata
    )
  • Configuring search, scroll, and indexing for efficient data retrieval
  • Setting up Master Data triggers for automated workflows
  • Managing schema lifecycle to avoid the 60-schema limit
Do not use this skill for:
  • General backend service patterns (use
    vtex-io-service-apps
    instead)
  • GraphQL schema definitions (use
    vtex-io-graphql-api
    instead)
  • Manifest and builder configuration (use
    vtex-io-app-structure
    instead)
当你的VTEX IO应用需要存储自定义数据(评论、心愿单、表单提交记录、配置信息)、查询或筛选这些数据,或者设置由数据变更触发的自动化工作流时,可使用本技能。
  • 使用
    masterdata
    构建器定义数据实体和JSON Schema
  • 通过MasterDataClient(
    ctx.clients.masterdata
    )执行CRUD操作
  • 配置搜索、滚动和索引以实现高效的数据检索
  • 设置Master Data触发器以实现自动化工作流
  • 管理模式生命周期,避免60个模式的限制
不适用本技能的场景:
  • 通用后端服务模式(请使用
    vtex-io-service-apps
  • GraphQL模式定义(请使用
    vtex-io-graphql-api
  • 清单与构建器配置(请使用
    vtex-io-app-structure

Decision rules

决策规则

  • A data entity is a named collection of documents (analogous to a database table). A JSON Schema defines structure, validation, and indexing.
  • When using the
    masterdata
    builder, entities are defined by folder structure:
    masterdata/{entityName}/schema.json
    . The builder creates entities named
    {vendor}_{appName}_{entityName}
    .
  • Use
    ctx.clients.masterdata
    or
    masterDataFor
    from
    @vtex/clients
    for all CRUD operations — never direct REST calls.
  • All fields used in
    where
    clauses MUST be declared in the schema's
    v-indexed
    array for efficient querying.
  • Use
    searchDocuments
    for bounded result sets (known small size, max page size 100). Use
    scrollDocuments
    for large/unbounded result sets.
  • The
    masterdata
    builder creates a new schema per app version. Clean up unused schemas to avoid the 60-schema-per-entity hard limit.
MasterDataClient methods:
MethodDescription
getDocument
Retrieve a single document by ID
createDocument
Create a new document, returns generated ID
createOrUpdateEntireDocument
Upsert a complete document
createOrUpdatePartialDocument
Upsert partial fields (patch)
updateEntireDocument
Replace all fields of an existing document
updatePartialDocument
Update specific fields only
deleteDocument
Delete a document by ID
searchDocuments
Search with filters, pagination, and field selection
searchDocumentsWithPaginationInfo
Search with total count metadata
scrollDocuments
Iterate over large result sets
Search
where
clause syntax:
text
where: "productId=12345 AND approved=true"
where: "rating>3"
where: "createdAt between 2025-01-01 AND 2025-12-31"
Architecture:
text
VTEX IO App (node builder)
  ├── ctx.clients.masterdata.createDocument()
  │       │
  │       ▼
  │   Master Data v2 API
  │       │
  │       ├── Validates against JSON Schema
  │       ├── Indexes declared fields
  │       └── Fires triggers (if conditions match)
  │             │
  │             ▼
  │         HTTP webhook / Email / Action
  └── ctx.clients.masterdata.searchDocuments()
      Master Data v2 (reads indexed fields for efficient queries)
  • 数据实体是文档的命名集合(类似数据库表)。JSON Schema用于定义结构、验证规则和索引配置。
  • 使用
    masterdata
    构建器时,实体通过文件夹结构定义:
    masterdata/{entityName}/schema.json
    。构建器会创建名为
    {vendor}_{appName}_{entityName}
    的实体。
  • 所有CRUD操作必须使用
    ctx.clients.masterdata
    @vtex/clients
    中的
    masterDataFor
    ——绝不允许直接调用REST接口。
  • 所有在
    where
    子句中使用的字段必须在模式的
    v-indexed
    数组中声明,以实现高效查询。
  • 对于有限结果集(已知数据量较小,最大页面大小为100),使用
    searchDocuments
    ;对于大型/无限结果集,使用
    scrollDocuments
  • masterdata
    构建器会为每个应用版本创建新的模式。需清理未使用的模式,避免触发每个实体最多60个模式的硬限制。
MasterDataClient方法:
方法描述
getDocument
根据ID检索单个文档
createDocument
创建新文档,返回生成的ID
createOrUpdateEntireDocument
全量插入或更新文档
createOrUpdatePartialDocument
部分字段插入或更新(补丁操作)
updateEntireDocument
替换现有文档的所有字段
updatePartialDocument
仅更新指定字段
deleteDocument
根据ID删除文档
searchDocuments
带筛选、分页和字段选择的搜索
searchDocumentsWithPaginationInfo
包含总条数元数据的搜索
scrollDocuments
遍历大型结果集
搜索
where
子句语法:
text
where: "productId=12345 AND approved=true"
where: "rating>3"
where: "createdAt between 2025-01-01 AND 2025-12-31"
架构:
text
VTEX IO App (node builder)
  ├── ctx.clients.masterdata.createDocument()
  │       │
  │       ▼
  │   Master Data v2 API
  │       │
  │       ├── 基于JSON Schema验证
  │       ├── 为声明的字段建立索引
  │       └── 触发触发器(若条件匹配)
  │             │
  │             ▼
  │         HTTP webhook / 邮件 / 动作
  └── ctx.clients.masterdata.searchDocuments()
      Master Data v2(读取索引字段以实现高效查询)

Hard constraints

硬约束

Constraint: Use MasterDataClient — Never Direct REST Calls

约束:使用MasterDataClient — 禁止直接调用REST接口

All Master Data operations in VTEX IO apps MUST go through the MasterDataClient (
ctx.clients.masterdata
) or the
masterDataFor
factory from
@vtex/clients
. You MUST NOT make direct REST calls to
/api/dataentities/
endpoints.
Why this matters
The MasterDataClient handles authentication token injection, request routing, retry logic, caching, and proper error handling. Direct REST calls bypass all of these, requiring manual auth headers, pagination, and retry logic. When the VTEX auth token format changes, direct calls break while the client handles it transparently.
Detection
If you see direct HTTP calls to URLs matching
/api/dataentities/
,
api.vtex.com/api/dataentities
, or raw fetch/axios calls targeting Master Data endpoints, warn the developer to use
ctx.clients.masterdata
instead.
Correct
typescript
// Using MasterDataClient through ctx.clients
export async function getReview(ctx: Context, next: () => Promise<void>) {
  const { id } = ctx.query

  const review = await ctx.clients.masterdata.getDocument<Review>({
    dataEntity: 'reviews',
    id: id as string,
    fields: ['id', 'productId', 'author', 'rating', 'title', 'text', 'approved'],
  })

  ctx.status = 200
  ctx.body = review
  await next()
}
Wrong
typescript
// Direct REST call to Master Data — bypasses client infrastructure
import axios from 'axios'

export async function getReview(ctx: Context, next: () => Promise<void>) {
  const { id } = ctx.query

  // No caching, no retry, no proper auth, no metrics
  const response = await axios.get(
    `https://api.vtex.com/api/dataentities/reviews/documents/${id}`,
    {
      headers: {
        'X-VTEX-API-AppKey': process.env.VTEX_APP_KEY,
        'X-VTEX-API-AppToken': process.env.VTEX_APP_TOKEN,
      },
    }
  )

  ctx.status = 200
  ctx.body = response.data
  await next()
}

VTEX IO应用中的所有Master Data操作必须通过MasterDataClient(
ctx.clients.masterdata
)或
@vtex/clients
中的
masterDataFor
工厂执行。绝对不允许直接调用
/api/dataentities/
端点的REST接口。
为什么这很重要
MasterDataClient会处理认证令牌注入、请求路由、重试逻辑、缓存和正确的错误处理。直接调用REST接口会绕过所有这些机制,需要手动处理认证头、分页和重试逻辑。当VTEX认证令牌格式变更时,直接调用会失效,而客户端会自动适配变更。
检测方式
若发现直接HTTP调用匹配
/api/dataentities/
api.vtex.com/api/dataentities
的URL,或使用raw fetch/axios调用Master Data端点,需提醒开发者改用
ctx.clients.masterdata
正确示例
typescript
// 通过ctx.clients使用MasterDataClient
export async function getReview(ctx: Context, next: () => Promise<void>) {
  const { id } = ctx.query

  const review = await ctx.clients.masterdata.getDocument<Review>({
    dataEntity: 'reviews',
    id: id as string,
    fields: ['id', 'productId', 'author', 'rating', 'title', 'text', 'approved'],
  })

  ctx.status = 200
  ctx.body = review
  await next()
}
错误示例
typescript
// 直接调用Master Data的REST接口 — 绕过客户端基础设施
import axios from 'axios'

export async function getReview(ctx: Context, next: () => Promise<void>) {
  const { id } = ctx.query

  // 无缓存、无重试、无正确认证、无指标监控
  const response = await axios.get(
    `https://api.vtex.com/api/dataentities/reviews/documents/${id}`,
    {
      headers: {
        'X-VTEX-API-AppKey': process.env.VTEX_APP_KEY,
        'X-VTEX-API-AppToken': process.env.VTEX_APP_TOKEN,
      },
    }
  )

  ctx.status = 200
  ctx.body = response.data
  await next()
}

Constraint: Define JSON Schemas for All Data Entities

约束:为所有数据实体定义JSON Schema

Every data entity your app uses MUST have a corresponding JSON Schema, either via the
masterdata
builder (recommended) or created via the Master Data API before the app is deployed.
Why this matters
Without a schema, Master Data stores documents as unstructured JSON. This means no field validation, no indexing (making search extremely slow on large datasets), no type safety, and no trigger support. Queries on unindexed fields perform full scans, which can time out or hit rate limits.
Detection
If the app creates or searches documents in a data entity but no JSON Schema exists for that entity (either in the
masterdata/
builder directory or via API), warn the developer to define a schema.
Correct
json
{
  "$schema": "http://json-schema.org/schema#",
  "title": "review-schema-v1",
  "type": "object",
  "properties": {
    "productId": {
      "type": "string"
    },
    "author": {
      "type": "string"
    },
    "rating": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5
    },
    "title": {
      "type": "string",
      "maxLength": 200
    },
    "text": {
      "type": "string",
      "maxLength": 5000
    },
    "approved": {
      "type": "boolean"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    }
  },
  "required": ["productId", "rating", "title", "text"],
  "v-default-fields": ["productId", "author", "rating", "title", "approved", "createdAt"],
  "v-indexed": ["productId", "author", "approved", "rating", "createdAt"]
}
Wrong
typescript
// Saving documents without any schema — no validation, no indexing
await ctx.clients.masterdata.createDocument({
  dataEntity: 'reviews',
  fields: {
    productId: '12345',
    rating: 'five', // String instead of number — no validation!
    title: 123,     // Number instead of string — no validation!
  },
})

// Searching on unindexed fields — full table scan, will time out on large datasets
await ctx.clients.masterdata.searchDocuments({
  dataEntity: 'reviews',
  where: 'productId=12345',  // productId is not indexed — very slow
  fields: ['id', 'rating'],
  pagination: { page: 1, pageSize: 10 },
})

应用使用的每个数据实体必须有对应的JSON Schema,推荐通过
masterdata
构建器定义,或在应用部署前通过Master Data API创建。
为什么这很重要
没有模式的话,Master Data会以无结构JSON的形式存储文档。这意味着没有字段验证、没有索引(大型数据集上的搜索会极慢)、没有类型安全,也不支持触发器。对未索引字段的查询会触发全文档扫描,可能导致超时或触发速率限制。
检测方式
若应用在某个数据实体中创建或搜索文档,但该实体没有对应的JSON Schema(既不在
masterdata/
构建器目录中,也未通过API创建),需提醒开发者定义模式。
正确示例
json
{
  "$schema": "http://json-schema.org/schema#",
  "title": "review-schema-v1",
  "type": "object",
  "properties": {
    "productId": {
      "type": "string"
    },
    "author": {
      "type": "string"
    },
    "rating": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5
    },
    "title": {
      "type": "string",
      "maxLength": 200
    },
    "text": {
      "type": "string",
      "maxLength": 5000
    },
    "approved": {
      "type": "boolean"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    }
  },
  "required": ["productId", "rating", "title", "text"],
  "v-default-fields": ["productId", "author", "rating", "title", "approved", "createdAt"],
  "v-indexed": ["productId", "author", "approved", "rating", "createdAt"]
}
错误示例
typescript
// 无模式存储文档 — 无验证、无索引
await ctx.clients.masterdata.createDocument({
  dataEntity: 'reviews',
  fields: {
    productId: '12345',
    rating: 'five', // 字符串而非数字 — 无验证!
    title: 123,     // 数字而非字符串 — 无验证!
  },
})

// 查询未索引字段 — 全表扫描,大型数据集上会超时
await ctx.clients.masterdata.searchDocuments({
  dataEntity: 'reviews',
  where: 'productId=12345',  // productId未索引 — 极慢
  fields: ['id', 'rating'],
  pagination: { page: 1, pageSize: 10 },
})

Constraint: Manage Schema Versions to Avoid the 60-Schema Limit

约束:管理模式版本以避免60个模式的限制

Master Data v2 data entities have a limit of 60 schemas per entity. When using the
masterdata
builder, each app version linked or installed creates a new schema. You MUST delete unused schemas regularly.
Why this matters
Once the 60-schema limit is reached, the
masterdata
builder cannot create new schemas, and linking or installing new app versions will fail. This is a hard platform limit that cannot be increased.
Detection
If the app has been through many link/install cycles, warn the developer to check and clean up old schemas using the Delete Schema API.
Correct
bash
undefined
Master Data v2的数据实体有每个实体最多60个模式的限制。使用
masterdata
构建器时,每个链接或安装的应用版本都会创建新的模式。必须定期删除未使用的模式。
为什么这很重要
一旦达到60个模式的限制,
masterdata
构建器将无法创建新的模式,链接或安装新应用版本会失败。这是平台的硬限制,无法调整。
检测方式
若应用经历了多次链接/安装周期,需提醒开发者通过删除模式API检查并清理旧模式。
正确示例
bash
undefined

Periodically clean up unused schemas

定期清理未使用的模式

List schemas for the entity

列出实体的所有模式

curl -X GET "https://{account}.vtexcommercestable.com.br/api/dataentities/reviews/schemas"
-H "X-VTEX-API-AppKey: {appKey}"
-H "X-VTEX-API-AppToken: {appToken}"
curl -X GET "https://{account}.vtexcommercestable.com.br/api/dataentities/reviews/schemas"
-H "X-VTEX-API-AppKey: {appKey}"
-H "X-VTEX-API-AppToken: {appToken}"

Delete old schemas that are no longer in use

删除不再使用的旧模式

curl -X DELETE "https://{account}.vtexcommercestable.com.br/api/dataentities/reviews/schemas/old-schema-name"
-H "X-VTEX-API-AppKey: {appKey}"
-H "X-VTEX-API-AppToken: {appToken}"

**Wrong**

```text
Never cleaning up schemas during development.
After 60 link cycles, the builder fails:
"Error: Maximum number of schemas reached for entity 'reviews'"
The app cannot be linked or installed until old schemas are deleted.
curl -X DELETE "https://{account}.vtexcommercestable.com.br/api/dataentities/reviews/schemas/old-schema-name"
-H "X-VTEX-API-AppKey: {appKey}"
-H "X-VTEX-API-AppToken: {appToken}"

**错误示例**

```text
开发过程中从不清理模式。
经过60次链接周期后,构建器失败:
"Error: Maximum number of schemas reached for entity 'reviews'"
必须删除旧模式后,才能再次链接或安装应用。

Preferred pattern

推荐实践

Add the masterdata builder and policies:
json
{
  "builders": {
    "node": "7.x",
    "graphql": "1.x",
    "masterdata": "1.x"
  },
  "policies": [
    {
      "name": "outbound-access",
      "attrs": {
        "host": "api.vtex.com",
        "path": "/api/*"
      }
    },
    {
      "name": "ADMIN_DS"
    }
  ]
}
Define data entity schemas:
json
{
  "$schema": "http://json-schema.org/schema#",
  "title": "review-schema-v1",
  "type": "object",
  "properties": {
    "productId": {
      "type": "string"
    },
    "author": {
      "type": "string"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "rating": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5
    },
    "title": {
      "type": "string",
      "maxLength": 200
    },
    "text": {
      "type": "string",
      "maxLength": 5000
    },
    "approved": {
      "type": "boolean"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    }
  },
  "required": ["productId", "rating", "title", "text"],
  "v-default-fields": ["productId", "author", "rating", "title", "approved", "createdAt"],
  "v-indexed": ["productId", "author", "approved", "rating", "createdAt"],
  "v-cache": false
}
Set up the client with
masterDataFor
:
typescript
// node/clients/index.ts
import { IOClients } from '@vtex/api'
import { masterDataFor } from '@vtex/clients'

interface Review {
  id: string
  productId: string
  author: string
  email: string
  rating: number
  title: string
  text: string
  approved: boolean
  createdAt: string
}

export class Clients extends IOClients {
  public get reviews() {
    return this.getOrSet('reviews', masterDataFor<Review>('reviews'))
  }
}
Implement CRUD operations:
typescript
// node/resolvers/reviews.ts
import type { ServiceContext } from '@vtex/api'
import type { Clients } from '../clients'

type Context = ServiceContext<Clients>

export const queries = {
  reviews: async (
    _root: unknown,
    args: { productId: string; page?: number; pageSize?: number },
    ctx: Context
  ) => {
    const { productId, page = 1, pageSize = 10 } = args

    const results = await ctx.clients.reviews.search(
      { page, pageSize },
      ['id', 'productId', 'author', 'rating', 'title', 'text', 'createdAt', 'approved'],
      '',  // sort
      `productId=${productId} AND approved=true`
    )

    return results
  },
}

export const mutations = {
  createReview: async (
    _root: unknown,
    args: { input: { productId: string; rating: number; title: string; text: string } },
    ctx: Context
  ) => {
    const { input } = args
    const email = ctx.vtex.storeUserEmail ?? 'anonymous@store.com'

    const response = await ctx.clients.reviews.save({
      ...input,
      author: email.split('@')[0],
      email,
      approved: false,
      createdAt: new Date().toISOString(),
    })

    return ctx.clients.reviews.get(response.DocumentId, [
      'id', 'productId', 'author', 'rating', 'title', 'text', 'createdAt', 'approved',
    ])
  },

  deleteReview: async (
    _root: unknown,
    args: { id: string },
    ctx: Context
  ) => {
    await ctx.clients.reviews.delete(args.id)
    return true
  },
}
Configure triggers (optional):
json
{
  "name": "notify-moderator-on-new-review",
  "active": true,
  "condition": "approved=false",
  "action": {
    "type": "email",
    "provider": "default",
    "subject": "New review pending moderation",
    "to": ["moderator@mystore.com"],
    "body": "A new review has been submitted for product {{productId}} by {{author}}."
  },
  "retry": {
    "times": 3,
    "delay": { "addMinutes": 5 }
  }
}
Wire into Service:
typescript
// node/index.ts
import type { ParamsContext, RecorderState } from '@vtex/api'
import { Service } from '@vtex/api'

import { Clients } from './clients'
import { queries, mutations } from './resolvers/reviews'

export default new Service<Clients, RecorderState, ParamsContext>({
  clients: {
    implementation: Clients,
    options: {
      default: {
        retries: 2,
        timeout: 5000,
      },
    },
  },
  graphql: {
    resolvers: {
      Query: queries,
      Mutation: mutations,
    },
  },
})
添加masterdata构建器和策略:
json
{
  "builders": {
    "node": "7.x",
    "graphql": "1.x",
    "masterdata": "1.x"
  },
  "policies": [
    {
      "name": "outbound-access",
      "attrs": {
        "host": "api.vtex.com",
        "path": "/api/*"
      }
    },
    {
      "name": "ADMIN_DS"
    }
  ]
}
定义数据实体模式:
json
{
  "$schema": "http://json-schema.org/schema#",
  "title": "review-schema-v1",
  "type": "object",
  "properties": {
    "productId": {
      "type": "string"
    },
    "author": {
      "type": "string"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "rating": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5
    },
    "title": {
      "type": "string",
      "maxLength": 200
    },
    "text": {
      "type": "string",
      "maxLength": 5000
    },
    "approved": {
      "type": "boolean"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    }
  },
  "required": ["productId", "rating", "title", "text"],
  "v-default-fields": ["productId", "author", "rating", "title", "approved", "createdAt"],
  "v-indexed": ["productId", "author", "approved", "rating", "createdAt"],
  "v-cache": false
}
使用
masterDataFor
配置客户端:
typescript
// node/clients/index.ts
import { IOClients } from '@vtex/api'
import { masterDataFor } from '@vtex/clients'

interface Review {
  id: string
  productId: string
  author: string
  email: string
  rating: number
  title: string
  text: string
  approved: boolean
  createdAt: string
}

export class Clients extends IOClients {
  public get reviews() {
    return this.getOrSet('reviews', masterDataFor<Review>('reviews'))
  }
}
实现CRUD操作:
typescript
// node/resolvers/reviews.ts
import type { ServiceContext } from '@vtex/api'
import type { Clients } from '../clients'

type Context = ServiceContext<Clients>

export const queries = {
  reviews: async (
    _root: unknown,
    args: { productId: string; page?: number; pageSize?: number },
    ctx: Context
  ) => {
    const { productId, page = 1, pageSize = 10 } = args

    const results = await ctx.clients.reviews.search(
      { page, pageSize },
      ['id', 'productId', 'author', 'rating', 'title', 'text', 'createdAt', 'approved'],
      '',  // 排序
      `productId=${productId} AND approved=true`
    )

    return results
  },
}

export const mutations = {
  createReview: async (
    _root: unknown,
    args: { input: { productId: string; rating: number; title: string; text: string } },
    ctx: Context
  ) => {
    const { input } = args
    const email = ctx.vtex.storeUserEmail ?? 'anonymous@store.com'

    const response = await ctx.clients.reviews.save({
      ...input,
      author: email.split('@')[0],
      email,
      approved: false,
      createdAt: new Date().toISOString(),
    })

    return ctx.clients.reviews.get(response.DocumentId, [
      'id', 'productId', 'author', 'rating', 'title', 'text', 'createdAt', 'approved',
    ])
  },

  deleteReview: async (
    _root: unknown,
    args: { id: string },
    ctx: Context
  ) => {
    await ctx.clients.reviews.delete(args.id)
    return true
  },
}
配置触发器(可选):
json
{
  "name": "notify-moderator-on-new-review",
  "active": true,
  "condition": "approved=false",
  "action": {
    "type": "email",
    "provider": "default",
    "subject": "新评论待审核",
    "to": ["moderator@mystore.com"],
    "body": "用户{{author}}提交了关于产品{{productId}}的新评论。"
  },
  "retry": {
    "times": 3,
    "delay": { "addMinutes": 5 }
  }
}
接入服务:
typescript
// node/index.ts
import type { ParamsContext, RecorderState } from '@vtex/api'
import { Service } from '@vtex/api'

import { Clients } from './clients'
import { queries, mutations } from './resolvers/reviews'

export default new Service<Clients, RecorderState, ParamsContext>({
  clients: {
    implementation: Clients,
    options: {
      default: {
        retries: 2,
        timeout: 5000,
      },
    },
  },
  graphql: {
    resolvers: {
      Query: queries,
      Mutation: mutations,
    },
  },
})

Common failure modes

常见失败场景

  • Direct REST calls to /api/dataentities/: Using
    axios
    or
    fetch
    to call Master Data endpoints bypasses the client infrastructure — no auth, no caching, no retries. Use
    ctx.clients.masterdata
    or
    masterDataFor
    instead.
  • Searching without indexed fields: Queries on non-indexed fields trigger full document scans. For large datasets, this causes timeouts and rate limit errors. Ensure all
    where
    clause fields are in the schema's
    v-indexed
    array.
  • Not paginating search results: Master Data v2 has a maximum page size of 100 documents. Requesting more silently returns only up to the limit. Use proper pagination or
    scrollDocuments
    for large result sets.
  • Ignoring the 60-schema limit: Each app version linked/installed creates a new schema. After 60 link cycles, the builder fails. Periodically clean up unused schemas via the Delete Schema API.
  • 直接调用/api/dataentities/的REST接口:使用
    axios
    fetch
    调用Master Data端点会绕过客户端基础设施——无认证、无缓存、无重试。应改用
    ctx.clients.masterdata
    masterDataFor
  • 查询未索引字段:对未索引字段的查询会触发全文档扫描。大型数据集上会导致超时和速率限制错误。需确保所有
    where
    子句中的字段都在模式的
    v-indexed
    数组中。
  • 未对搜索结果分页:Master Data v2的最大页面大小为100条文档。请求超过该数量会静默返回最多100条。需使用正确的分页,或对大型结果集使用
    scrollDocuments
  • 忽略60个模式的限制:每个链接/安装的应用版本都会创建新的模式。经过60次链接周期后,构建器会失败。需定期通过删除模式API清理未使用的模式。

Review checklist

审核清单

  • Is the
    masterdata
    builder declared in
    manifest.json
    ?
  • Do all data entities have JSON Schemas with proper field definitions?
  • Are all
    where
    clause fields declared in
    v-indexed
    ?
  • Are CRUD operations using
    ctx.clients.masterdata
    or
    masterDataFor
    (no direct REST calls)?
  • Is pagination properly handled (max 100 per page, scroll for large sets)?
  • Is there a plan for schema cleanup to avoid the 60-schema limit?
  • Are required policies (
    outbound-access
    ,
    ADMIN_DS
    ) declared in the manifest?
  • manifest.json
    中是否声明了
    masterdata
    构建器?
  • 所有数据实体是否都有定义了正确字段的JSON Schema?
  • 所有
    where
    子句中的字段是否都在
    v-indexed
    中声明?
  • CRUD操作是否使用了
    ctx.clients.masterdata
    masterDataFor
    (无直接REST调用)?
  • 是否正确处理了分页(每页最多100条,大型数据集使用scroll)?
  • 是否有清理模式的计划,以避免60个模式的限制?
  • manifest
    中是否声明了必要的策略(
    outbound-access
    ADMIN_DS
    )?

Reference

参考链接