---
title: Product import, management and search
description: Technical diagrams of how a product gets into Leitagu (sync, admin, corrections, options), who may change what, how it is cached, and how the chat and the catalogue search it.
section: platform
order: 2
updated: 2026-10-21
---
Four pictures show what happens to a product, from a store's data to a shopper's screen, and how the chat and the catalogue find it. Each picture has the same steps written out under it, for readers who can't see images. For the short version see [Platform architecture](architecture.md#product-data-flow).

## How a product gets in

![Four steps: store data, read safely, understand, save. A sync starts from a button, a schedule, a CSV upload or a staff tool.](/diagrams/product-import.svg)

1. **Store data.** Shopify, WooCommerce, a product feed or a CSV file. Staff can also add a product by hand in the admin app, which needs no sync.
2. **Read safely.** Leitagu reads public addresses only, obeys the shop's `robots.txt`, and limits size and time. A store's secrets are stored encrypted. Limits: Shopify 5,000 products and 100 variants each; WooCommerce 10,000 products.
3. **Understand.** Each item becomes a Leitagu product: category, size, colour, material, wood, style, stock, delivery, barcode and brand. Colours, covers and leg finishes become choices. An item with no price, no name or an unknown category is skipped and listed as an issue.
4. **Save.** One row per product. The choices are kept as a list, and only odd combinations (their own price, sold out, not sold) are stored as exceptions. A product that has gone from the source is hidden, never deleted. A product with no size is saved but hidden from shoppers, because it can't be fitted to a room. The sync ends with a report (ok, partly or failed, with each issue), and the shop sees the change within about 5 seconds.
5. **Check and draw.** Every saved product then goes through the [product pipeline](product-pipeline.md): its data is checked, its drawing for the 3D room is worked out, and doubtful products wait for the Leitagu team's review.

A sync starts from "Sync now" in the partner or admin app, from the hourly or daily schedule, from a CSV upload, or from the staff AI tool. Only one sync runs per connection at a time. See [Options and variants](../partners/integrations.md#options-and-variants) for the choices.

## Who can change a product

![A product has two layers: the store's data, and corrections. Four groups of people change them; some things hide a product.](/diagrams/product-ownership.svg)

- **Layer 1, from the store.** Name, price, size, colour, stock, picture and choices. Every sync overwrites it.
- **Layer 2, corrections.** A short list of fields. They are kept when the next sync runs and applied on top.
- **The store** (partner app) corrects its own products. **The Leitagu team** (admin app) makes the same corrections on products from a connection, and edits directly only products made by hand. Nobody writes layer 1 of a synced product by hand.
- **Hidden from shoppers** when the store is paused or not yet proven, when the team hid the connection, when the store hid the product, or when it has no size. Nothing is hidden automatically when data goes out of date: after 72 hours without a good sync the team sees it and decides.
- Problems such as "no size" or "no colour" are worked out every time a product is read. Every change by the team or a store is written to the audit log.

Every app keeps all products in memory and checks every few seconds whether the number of products or the latest change time moved, then reloads. Anything that changes a product must update its change time, or other apps will not notice.

## How the chat finds a product

![Seven steps: you write, Claude or a keyword parser understands, settings split into must and like, then for each product the best option, the exact combination, the filters and the score; results are sorted and shown with a reason.](/diagrams/search-chat.svg)

1. **You write** a sentence, tap a chip, or send a room photo.
2. **Understand.** Claude reads it; without an API key a keyword parser does (Estonian and English).
3. **Settings.** What must hold filters products: category, size, budget, stores, "only oak", "no glass". What you only like ranks them: colour, wood, style.
4. **Pick the best option.** For a product with choices, each colour, cover and leg finish is tried once and the best are combined.
5. **Check the exact combination.** Is it sold, in stock and within budget? If not, the next best.
6. **Filters.** A product that fails a "must" is left out. One at most 12% over a size or price limit is shown and labelled.
7. **Score.** A 0 to 100% match per attribute, added up.

Results are sorted best first and grouped as very close, close and other. Equal scores put products on sale first, then the lower price. Each card says why it matches. Suggestions for a room run the same search once per kind of furniture.

**Nothing paid changes the order.** A store decides what its product is, never where it ranks.

## How a product with choices is matched

![A sofa in 10 colours and 8 leg finishes: try each value once, combine the best, then check the exact combination.](/diagrams/search-options.svg)

1. Each option changes its own attributes, so every value of every option is tried once: 10 + 8 comparisons, not 80.
2. The best of each are combined: here grey and walnut.
3. The exact combination is checked. If it is not sold, is sold out or has its own price that breaks a filter, the next best value is used. A sold-out choice is shown only if nothing else fits.

Size is not a choice yet, because it changes the dimensions a room needs.

## How the catalogue finds a product

![Four steps: filters in the address, read the address, filter, sort.](/diagrams/search-catalogue.svg)

1. The address holds the filters, for example `/catalogue?category=sofa&colour=blue&priceMax=900`. Anyone can open it.
2. Unknown values are dropped and the address is cleaned up.
3. The same "must" filters as the chat run, with no near misses. A product with choices passes if any choice does, and opens on that choice.
4. A plain sort: price, newest, soonest available or store, 24 a page. Never a score, never paid.

## Where to look in the code

Paths are in `packages/core/src` unless they start with `apps/`.

| Question | File |
| --- | --- |
| What does a source give us? | `server/integrations/sources.ts`, `fetchers.ts` |
| How is a product mapped? | `server/integrations/normalize.ts`, `variants.ts` |
| What does a sync do? | `server/integrations/sync.ts` |
| How is a product read and cached? | `server/data.ts` (`rowToProduct`, `getProducts`) |
| Which fields can be corrected? | `server/data.ts` (`OVERRIDABLE`), `server/validate.ts` (`OverridesSchema`) |
| How does the chat turn work? | `apps/web/src/lib/server/engine.ts`, `shared/parse.ts` |
| How are products matched? | `shared/search.ts`, `shared/rules.ts`, `shared/variants.ts` |
| How does the catalogue filter? | `shared/catalogue.ts` |

## Related pages

- [Platform architecture](architecture.md)
- [Product pipeline](product-pipeline.md)
- [Partner integrations guide](../partners/integrations.md)
- [How Leitagu works](../product/how-it-works.md)
- [Analytics definitions](../partners/analytics.md)
