Saleor Domain Expert
Purpose
Provide deep domain knowledge about the Saleor e-commerce platform and the Configurator's business logic for entity management, configuration, deployment, and synchronization.
When to Use
- Implementing new entity types or features
- Understanding entity identification patterns
- Working with deployment pipeline stages
- Debugging configuration synchronization issues
- Understanding business rules and constraints
Table of Contents
- Core Concepts
- Entity Identification System
- Deployment Pipeline
- Configuration Schema
- Bulk Operations
- Diff & Comparison Logic
- Common Patterns
- References
Core Concepts
What is Saleor Configurator?
A "commerce as code" CLI tool that enables declarative configuration management for Saleor e-commerce platforms. It allows developers to:
- Introspect: Download remote Saleor configuration to local YAML files
- Deploy: Apply local YAML configuration to remote Saleor instance
- Diff: Compare local and remote configurations
- Start: Interactive wizard for first-time setup
Configuration as Code Philosophy
- Single source of truth for store state
- Version-controlled configuration (YAML in git)
- Reproducible deployments across environments
- Declarative over imperative management
Entity Identification System
Critical Rule: Every entity has exactly ONE identification strategy.
Slug-Based Entities
Identified by slug field. Used for entities that need URL-friendly identifiers.
| Entity | Identifier Field | Example |
|---|---|---|
| Categories | slug | electronics |
| Channels | slug | default-channel |
| Collections | slug | summer-sale |
| Menus | slug | main-navigation |
| Products | slug | iphone-15-pro |
| Warehouses | slug | us-east-warehouse |
Implementation Pattern:
// Comparison uses slug const isSameEntity = (local: Category, remote: Category) => local.slug === remote.slug; // Lookups use slug const existing = await repository.findBySlug(entity.slug);
Name-Based Entities
Identified by name field. Used for internal configuration entities.
| Entity | Identifier Field | Example |
|---|---|---|
| ProductTypes | name | Physical Product |
| PageTypes | name | Blog Post |
| TaxClasses | name | Standard Rate |
| ShippingZones | name | North America |
| Attributes | name | Color |
Implementation Pattern:
// Comparison uses name const isSameEntity = (local: ProductType, remote: ProductType) => local.name === remote.name;
Singleton Entities
Only one instance exists. No identifier needed.
| Entity | Notes |
|---|---|
| Shop | Global store settings |
Deployment Pipeline
Stage Order (Dependencies)
Stages execute in specific order due to dependencies:
1. Validation β Pre-flight checks
2. Shop Settings β Global configuration
3. Product Types β Must exist before products
4. Page Types β Must exist before pages
5. Attributes β Used by product/page types
6. Categories β Product organization
7. Collections β Product groupings
8. Warehouses β Required for inventory
9. Shipping Zones β Geographic shipping rules
10. Products β Depends on types, categories
11. Tax Config β Tax rules and classes
12. Channels β Sales channels
13. Menus β Navigation (may reference products)
14. Models β Custom data models
Why Order Matters
Example: Cannot create a Product without its ProductType existing first.
# This product depends on "Physical Product" type products: - name: "iPhone 15" slug: "iphone-15" productType: "Physical Product" # Must exist!
Stage Execution Pattern
Each stage follows:
- Fetch: Get current remote state
- Compare: Diff local vs remote
- Plan: Determine creates/updates/deletes
- Execute: Apply changes with chunking
- Report: Log results and failures
Configuration Schema
Top-Level Structure
shop: # Global store settings channels: # Sales channel definitions taxClasses: # Tax rate classifications productTypes: # Product type templates pageTypes: # CMS page templates attributes: # Shared attribute definitions categories: # Product category hierarchy collections: # Dynamic product collections warehouses: # Fulfillment center definitions shippingZones: # Geographic shipping configurations products: # Product catalog menus: # Navigation menu structures models: # Custom data models
Attribute Types
Attributes can be of various types:
| Type | Description | Example Values |
|---|---|---|
DROPDOWN | Single select | ["Red", "Blue", "Green"] |
MULTISELECT | Multiple select | ["Feature A", "Feature B"] |
RICH_TEXT | HTML content | Rich text editor |
PLAIN_TEXT | Simple text | Text input |
BOOLEAN | True/false | Checkbox |
DATE | Date picker | 2024-01-15 |
DATE_TIME | Date and time | 2024-01-15T10:30:00 |
NUMERIC | Numbers | 42.5 |
SWATCH | Color/image swatch | Color picker |
FILE | File upload | Document/image |
REFERENCE | Entity reference | Links to other entities |
Reference Attributes (Special):
attributes: - name: "Related Products" type: REFERENCE entityType: PRODUCT # Must specify what it references
Bulk Operations
Chunking Strategy
Large operations are chunked to avoid timeouts and rate limits:
const CHUNK_SIZE = 50; // Default chunk size const chunks = splitIntoChunks(items, CHUNK_SIZE); for (const chunk of chunks) { await processChunk(chunk); // Rate limiting handled by urql retry exchange }
Rate Limit Handling
The GraphQL client handles HTTP 429 automatically:
- Exponential backoff with jitter
- Max 5 retries
- Network error recovery
Diff & Comparison Logic
Comparison Dimensions
For each entity type, comparison checks:
- Existence: Does entity exist remotely?
- Equality: Are all relevant fields equal?
- Children: Are nested structures equal?
Diff Result Types
type DiffAction = 'create' | 'update' | 'delete' | 'unchanged'; interface DiffResult<T> { action: DiffAction; local?: T; remote?: T; changes?: FieldChange[]; }
Comparator Pattern
Each entity has a dedicated comparator:
// src/core/diff/comparators/category-comparator.ts export const compareCategorys = ( local: Category[], remote: Category[] ): DiffResult<Category>[] => { // Match by slug // Compare relevant fields // Return diff results };
Common Patterns
Adding a New Entity Type
- Define Zod schema in
src/modules/config/schema/ - Create service in
src/modules/<entity>/ - Create repository with GraphQL operations
- Add comparator in
src/core/diff/comparators/ - Add deployment stage in pipeline
- Update schema documentation
Handling Entity Dependencies
// Check dependency exists before creating const productType = await productTypeRepository.findByName(product.productType); if (!productType) { throw new EntityDependencyError( `ProductType "${product.productType}" not found` ); }
References
For detailed information, see:
{baseDir}/.claude/skills/saleor-domain-expert/references/entity-identification.md- Complete entity identification rules{baseDir}/.claude/skills/saleor-domain-expert/references/deployment-stages.md- Pipeline stage details{baseDir}/.claude/skills/saleor-domain-expert/references/schema-patterns.md- YAML configuration patterns{baseDir}/docs/ENTITY_REFERENCE.md- Full entity documentation{baseDir}/docs/ARCHITECTURE.md- System architecture{baseDir}/src/modules/config/schema/schema.ts- Zod schema definitions
Related Skills
- Implementing entities: See
adding-entity-typesfor complete implementation workflow - Config schemas: See
designing-zod-schemasfor schema patterns - GraphQL operations: See
writing-graphql-operationsfor Saleor API integration
Quick Reference Rules
For condensed quick references, see:
.claude/rules/entity-development.md(automatically loaded when editingsrc/modules/**/*.ts).claude/rules/diff-engine.md(automatically loaded when editingsrc/core/diff/**/*.ts)