---
title: 'Iterating your schema'
description: 'Treat the first schema as a working draft. Use Chat and automations to find missing fields and relationships, then refine the model.'
---

import { Callout } from 'nextra/components';
import { Steps } from 'nextra/components';

# Iterating your schema

A useful schema is the one that can answer the questions your team actually asks. You deploy a first version so people and agents can work with real records. You then refine it whenever a question is harder to answer than the business already knows.

That loop is how Flexkit schemas get good. The first deploy is a working draft, not a verdict on the product or on your model.

## Schema is the contract agents query

Chat and automations do not invent a data warehouse. They walk the knowledge graph your schema describes — entities, attributes, and the relationships that connect them — through the generated [GraphQL API](/docs/api/graphql).

A schema that stores orders and line items can still fail a basic commercial question if that graph cannot *reach* the answer efficiently. Quantity on a line item is not the same thing as “units sold last six months” on a product. One is how the business records a sale. The other is how the business *asks* about sales.

The second shape has to be designed.

## Hard questions are design input

When Chat or an automation says it cannot aggregate, sort, or traverse the catalog efficiently, the agent is reporting a gap in the model. Typical signals:

- It can count related records but cannot **sum** a field from the parent entity.
- It can inspect a handful of candidates but cannot **rank** the whole collection.
- It can page thousands of rows but cannot **group** them by SKU, customer, or period.
- It leans on a nearby field (search popularity, last-updated time) because the real metric is missing.

Those replies are useful. They tell you which relationship is one-way, which total only exists as a scan, and which comment would have stopped the agent from using the wrong field.

<Callout type="info">
  A thin first schema is normal. Importing source data faithfully is a different job from exposing the questions operators ask every week. You will often need both.
</Callout>

## The refinement loop

<Steps>
### Ask a real question

Use [Agent Chat](/docs/ai/agent-chat) or a small [automation](/docs/automations) the way a teammate would: “What is our bestselling product of the last six months?”, “Which suppliers have the most open purchase orders?”, “Which articles are published but missing a hero image?”

### Read the limitation, not only the answer

Keep the agent’s explanation. The valuable part is often the constraint: too many rows to page, no inverse relationship, no sortable total, every order status included, gifts mixed into volume.

### Hand the finding to a coding agent

Give it the question, the agent’s reply, and the schema files. Ask it to propose the smallest model change that makes the question a normal query: an inverse relationship, a field you can sort, a clearer comment, or a [skill](/docs/ai/skills) that documents the intended operation.

### Deploy, then fill the new data

[Deploy the schema](/docs/schema/deployment-and-migrations), then backfill or start writing the new fields and links. A new attribute is empty until something computes it. A new inverse relationship only helps if the edges already exist, or you create them.

### Ask the question again

The same prompt should now resolve with a short GraphQL read — a sort and a limit, or a connection aggregate on one record — instead of a scan of the operational history.
</Steps>

## What to add when the graph is thin

Most “the agent cannot answer this” cases resolve with one of these changes.

**An inverse relationship.** Line items often point at a product while the product cannot see those lines. Adding the inverse lets you sum `quantity` or `lineTotal` for one SKU, filtered by date and status, through `salesOrderItemsConnection { aggregate { ... } }`.

**A field you can sort.** The generated API can aggregate along a relationship for a known parent. It cannot group every line in the catalog by SKU and return the top row. Rankings and rolling windows belong on the parent as stored fields — `unitsSoldLast180Days`, `openOrderCount`, `publishedAt` — computed on write or by a periodic job.

**Comments that name the meaning.** Agents read the model. “Catalog search ranking score, not units sold” prevents a confident wrong answer. “One edge per order, not per unit” prevents an order count from being reported as volume.

**A skill for the intended query.** Skills teach procedure. They do not create data. Use them after the fields exist, so the agent sorts `unitsSoldLast180Days` instead of paging order lines.

Combine them when the question needs both a fast ranking and an on-demand check. The inverse relationship verifies one product. The stored field ranks the catalog.

## A commerce example

A catalog with products, orders, and order lines can still miss “bestseller of the last six months.” Quantity lives on the line. The product has no path to those lines. Popularity, if present, is a storefront search score.

The model change is small and specific:

1. Expose `salesOrderItems` on `product` so a single SKU can sum units in a date range.
2. Store `unitsSoldLast180Days` (and lifetime `unitsSold` if you need all-time ranking) on `product`, excluding gifts and cancelled or refunded orders.
3. Comment `popularity` so agents do not treat it as sales.
4. Add a short skill: last six months means sort `unitsSoldLast180Days` descending and take `limit: 1`.

After deploy and backfill, the question is a list query — the same shape Desk already uses to sort a grid.

```graphql
query BestSellerLastSixMonths {
  products(sort: [{ unitsSoldLast180Days: DESC }], limit: 1) {
    name
    sku
    unitsSoldLast180Days
    brand {
      name
    }
  }
}
```

The operational history is still there for audit. The schema now also speaks the language of the question.

## Keep going

You will do this more than once. Each new workflow — forecasting, quality review, supplier performance — will ask the model for a total, a window, or a traversal it does not yet expose. That is progress: the team is using Flexkit for real work, and the schema is catching up to the business.

Start from the entities you have. Let the questions you cannot answer yet tell you what to add next.

- [Schema overview](/docs/schema)
- [Relationships and scopes](/docs/schema/relationships-and-scopes)
- [Deployment and migrations](/docs/schema/deployment-and-migrations)
- [Agent Chat](/docs/ai/agent-chat)
- [Skills](/docs/ai/skills)


---

[View full sitemap](/docs/sitemap.md)
