Skip to main content

SAAS configuration

Evolve manages SAAS service configuration through Terraform, the same infrastructure-as-code tool used for cloud resources. This means commercetools projects, CMS content models, search indices, and observability tools are all defined declaratively, version-controlled, and reproducible across environments.

This approach may be unfamiliar if you're used to configuring SAAS services through their web interfaces. The benefit is significant: spinning up a new environment (staging, demo, new client) is a single terraform apply that provisions everything, from cloud infrastructure to SAAS configurations, in one go. No manual clicking through admin panels, no forgotten settings, no configuration drift between environments.

What gets configured

Evolve includes Terraform configurations for all integrated SAAS services:

backend/configuration/
├── commercetools/ # Project settings, stores, channels,
│ # product types, tax categories
├── contentful/ # Locales, content types, editor interfaces
├── storyblok/ # Components, component groups
└── algolia/ # Indices, virtual indices, facet config

Each directory contains a self-contained Terraform module that can be applied independently or orchestrated through MACH Composer.

Commerce configuration

The commercetools Terraform provider manages the commerce backend: project settings, stores, channels, product types, and tax categories.

resource "commercetools_project_settings" "project" {
name = "my-project"
countries = ["NL", "DE", "GB"]
currencies = ["EUR", "GBP"]
languages = ["nl-NL", "en-GB", "de-DE"]

messages {
enabled = true
}

carts {
country_tax_rate_fallback_enabled = true
delete_days_after_last_modification = 90
}
}

resource "commercetools_store" "primary" {
key = "my-store"
name = { nl-NL = "My Store" }
languages = commercetools_project_settings.project.languages
countries = commercetools_project_settings.project.countries

distribution_channels = [
commercetools_channel.store.key
]
}

Product types, which define the attributes available on products, are also managed through Terraform. This ensures the data model is consistent across environments:

resource "commercetools_product_type" "fashion" {
key = "fashion"
name = "Fashion"
description = "Fashion product type"

attribute {
name = "brand"
label = { en-GB = "Brand", nl-NL = "Merk" }
constraint = "None"
type = { name = "text" }
searchable = true
}
}

CMS configuration

Both Contentful and Storyblok content models are defined in Terraform. This means the content types and components that content editors work with are version-controlled and consistent across environments.

Contentful

resource "contentful_contenttype" "hero" {
space_id = var.contentful_space_id
environment = var.contentful_environment
id = "hero"
name = "Hero"
display_field = "title"

fields = [
{
id = "title"
name = "Title"
type = "Text"
},
{
id = "image"
name = "Image"
type = "Link"
link_type = "Asset"
},
]
}

Storyblok

resource "storyblok_component" "hero" {
name = "hero"
space_id = var.storyblok_space_id
is_root = false
is_nestable = true

schema = {
title = {
position = 0
translatable = true
display_name = "Title"
required = true
type = "text"
}
image = {
position = 5
translatable = true
display_name = "Image"
required = true
type = "asset"
filetypes = ["images"]
}
}
}

Search configuration

Algolia indices, including facet configuration, searchable attributes, and sort order replicas, are managed through Terraform:

resource "algolia_index" "default" {
for_each = local.store_keys
name = "${each.value}_default"

attributes_config {
searchable_attributes = [
"name",
"description",
"variants.sku",
]
attributes_for_faceting = [
"startingPrice.centAmount",
"hierarchicalCategories.lvl0",
"variants.attributes.brand",
"variants.attributes.color.nl-NL",
"variants.attributes.size",
]
}
}

resource "algolia_virtual_index" "price_asc" {
for_each = local.store_keys
name = "${each.value}_price_asc"
primary_index_name = algolia_index.default[each.key].name

ranking_config {
custom_ranking = ["asc(startingPrice.centAmount)"]
}
}

Terraform providers

Evolve uses community-maintained Terraform providers for each SAAS service:

ServiceProviderSource
commercetoolslabd/commercetoolsRegistry
Contentfullabd/contentfulRegistry
Storybloklabd/storyblokRegistry
Algoliak-yomo/algoliaRegistry

MACH Composer integration

MACH Composer ties SAAS configuration into the deployment pipeline. Each SAAS service is registered as a plugin, and components declare which integrations they need:

mach_composer:
plugins:
commercetools:
source: mach-composer/commercetools
version: 0.2.1
storyblok:
source: mach-composer/storyblok
version: 0.0.3
algolia:
source: mach-composer/algolia
version: 0.1.0
sentry:
source: mach-composer/sentry
version: 0.1.3

SAAS credentials and project-specific settings are defined per environment. MACH Composer injects these as Terraform variables when applying configurations:

sites:
- identifier: my-project
commercetools:
project_key: my-project
client_id: ${var.secrets.commercetools.client_id}
client_secret: ${var.secrets.commercetools.client_secret}
storyblok:
space_id: 233248
token: ${var.secrets.storyblok.management_token}
algolia:
app_id: YWHL59LKQC
api_key: ${var.secrets.algolia.write_api_key}

Components reference their SAAS integrations, and MACH Composer ensures the right credentials and configurations are passed to each Terraform module:

components:
- name: commercetools-config
source: ../../backend/configuration/commercetools/
integrations:
- commercetools

- name: storyblok-config
source: ../../backend/configuration/storyblok/
integrations:
- commercetools
- storyblok

- name: algolia-config
source: ../../backend/configuration/algolia/
integrations:
- algolia

This means adding a new environment is a matter of creating a new MACH Composer configuration file with the right credentials. The Terraform modules handle the rest.