Skip to main content

Data model

Evolve defines its own GraphQL data model that is independent of any backing SAAS service. This is a deliberate design choice: by owning the data model, Evolve can integrate any commerce engine, CMS, or search backend behind the same schema. Clients consume a single, consistent API regardless of which vendors are running underneath.

Vendor independence

Each SAAS backend has its own data model (commercetools has ProductProjection, Contentful has Entry, Algolia has its own hit format). Evolve does not expose these directly. Instead, each domain service maps vendor-specific data into Evolve's own GraphQL types. This means:

  • Swapping vendors does not change the API. Replacing your CMS or search engine requires a new service implementation, not frontend changes.
  • Combining vendors is straightforward. A single query can return product data from the commerce engine and content from the CMS, merged by GraphQL Federation.
  • Custom data models are yours to define. You design the schema that fits your business, not the one your vendor prescribes.

Schema.org alignment

Evolve's data model follows schema.org conventions where applicable. Schema.org provides a shared vocabulary for structured data on the web, and aligning with it gives practical benefits:

  • Familiar naming for developers (e.g., Product, Offer, Brand)
  • Easier mapping to structured data for SEO (JSON-LD)
  • A well-documented reference for what fields mean

This is not a strict implementation of schema.org; the data model is shaped for e-commerce use cases and GraphQL conventions. But where schema.org provides a sensible name or structure, Evolve follows it.

Key types

The data model spans all domain services. Here are the central types across the main domains:

Products and catalog

type Product {
name: String!
slug: String!
brand: String
meta: PageMeta
breadcrumbs: [Breadcrumb!]
variant(sku: String): ProductVariant
variants: [ProductVariant!]!
}

type ProductVariant {
sku: String!
name: String
description: String
price: ProductPrice
availability: ProductAvailability
images: [ProductImage!]
attributes: [ProductAttribute!]
}

type ProductCategory {
name: String!
slug: String!
children: [ProductCategory!]
parent: ProductCategory
}

Cart and checkout

type Cart {
lineItems: [CartLineItem!]!
totalPrice: Money!
shippingAddress: Address
billingAddress: Address
availableShippingMethods: [ShippingMethod!]
availablePaymentMethods: [PaymentMethod!]
discountCodes: [DiscountCode!]
}

Customer and account

type Customer {
email: EmailAddress!
givenName: String
familyName: String
addresses: AddressConnection!
businessUnits: [BusinessUnit!]
}

Orders

type Order {
orderNumber: String!
status: OrderStatus!
lineItems: [OrderLineItem!]!
totalPrice: Money!
createdAt: DateTime!
}
info

These are simplified examples. The full schema includes many more fields, input types, and connections. You can browse the complete schema interactively using the schema viewer.

Evolve data model

Shared types

Several types are shared across services using the @shareable federation directive. This means multiple services can resolve the same type independently:

  • Money: represents a monetary value with centAmount and currencyCode
  • Address: postal address used by checkout, account, and order services
  • PageMeta: SEO metadata (title, description, open graph) used by CMS and catalog services
  • Breadcrumb: navigation breadcrumbs resolved by both CMS and catalog

See page model for details on how page-related types work across services.

Extending the data model

Evolve's data model is a foundation, not a ceiling. Because the architecture uses GraphQL Federation, you can extend it in several ways:

  • Add fields to existing types: create a new subgraph that extends an Evolve type with additional fields (e.g., adding a loyaltyPoints field to Customer)
  • Add new types: introduce entirely new types and queries in a custom subgraph (e.g., a WishList or StoreLocator type)
  • Override resolvers: replace how an existing field is resolved without changing the schema
# Example: extending Customer with loyalty points
# in a custom subgraph

type Customer @extends @key(fields: "id") {
id: ID! @external
loyaltyPoints: Int!
loyaltyTier: LoyaltyTier!
}

The gateway automatically merges your extensions into the supergraph. See customization and extensibility for detailed patterns and code examples.