## The Client

Erich Keller AG started as a traditional joinery back in 1951. By 1971, they built their first trading room workstation — eventually expanding into high-stakes control rooms like air traffic control, where ergonomics, tech, and sightlines must work together flawlessly.

Those workstations generate serious heat. In 1997, the team built the world’s first workstation cooling system right at the heat source. By 2005, that evolved into **Riotherm**, a room climate system that now handles heating and cooling for entire buildings. In 2022, **Talky** brought interior design, furniture, and acoustic ventilation together into a modular room-in-room system.

That left us with an interesting challenge: one company, two distinct brands, completely different audiences, and a product range spanning from a single desk to a building's climate system — plus 75 years of heritage to honor without turning the website into a digital museum.

## Why DatoCMS

We picked DatoCMS for three reasons, listed in the order they actually mattered during the project:

**We know it, and we like the people.** We have built a lot on DatoCMS and the experience has been consistently good — including the company behind it, both as engineers and as people to deal with. On a project this compressed, that counts for more than a feature checklist.

**We ran an honest comparison anyway.** We did a formal evaluation against Sanity before writing a single line of code. Both could have done the job, but DatoCMS won us over with a few key features:

-   **First-class localization:** Three languages natively supported out of the box — no plugins, no awkward data modeling decisions. Switching locales, per-locale publishing, and fallback rules just work. When you translate an entire site days before launch, this is a lifesaver.
-   **Turnkey media pipeline with Astro:** `responsiveImage` combined with the DatoCMS `<Image>` component and imgix under the hood saved us weeks of custom work across 3,000+ image assets. The video streaming also turned out to be a huge benefit.
    
-   **Modular Content mirrors Figma:** The design system was created as a modular section library; DatoCMS allowed our content model to reflect that kit directly.
-   **The editorial UI is good out of the box.** The client's team are not developers, and nobody had budget for building a nice editing experience.
    

Where Sanity is genuinely stronger: the flexibility of the editing experience. The studio is code, and with AI in the loop you can build really nice editorial UX in it, fast. DatoCMS's answer is plugins — we wrote five field extensions, they do a lot, and they are less seamlessly integrated than native fields.

What you get back is stability. A Sanity studio is effectively a custom UI, and custom UI has to be maintained. On an eleven-week build that a small team looks after afterwards, that trade went to DatoCMS. Visual editing we covered with Web Previews and click-to-edit; schema-as-code we built ourselves, and got more control than a studio repo would have given us.

## Content Architecture: One Page Type, 45 Blocks

The usual instinct on a project this size is to build distinct page types: product pages, solution pages, case studies, landing pages. We decided to do the exact opposite.

**The entire site uses essentially one page model** — `cms_page`, structured as a tree — plus a single homepage record. A page's URL is constructed automatically from locale + parent slugs + slug. Navigation, breadcrumbs, sitemaps, language switchers, and parent labels all derive from that single tree structure. Move a page in the UI, and the whole site re-routes cleanly around it.

Everything else is a **block**. We built 45 of them, covering elements that traditional sites turn into rigid templates:

-   Reference listings with taxonomy filters
-   Team listings grouped by department
    
-   Product families with sticky scroll-spy navigation
-   Job openings, interactive location maps, comparison sliders, and spec tables
    

**A collection is just a section you drop anywhere, not a page type you have to engineer.** This single architectural choice allowed 72 dynamic pages to replace what normally requires dozens of static templates — enabling editors to build full landing pages without filing a developer request.

## Schema as Code — and why it mattered more with AI

DatoCMS lets you model schemas in the web UI, but we wanted our schema in Git: reviewable, version-controlled, and reproducible. We wrote the schema in the repository as **typed declarations**, paired with an idempotent reconciler script.

Bash

```bash
npm run datocms:schema:plan   # Dry run — shows exact pending changesnpm run datocms:schema:sync   # Applies changes, then updates GraphQL types
```

A single configuration file holds every field key as the single source of truth. Types derive from it directly, meaning a block referencing another non-existent block fails at compile time rather than breaking in production.

**This became probably our most critical decision for AI-assisted workflows.** An AI agent interacting with a web UI has to interrogate an API repeatedly. A schema stored in the local repository allows the agent to *read*, grep, and type-check locally.

Questions like *"What fields does this block have?"* became simple file reads instead of external API round-trips. Compile errors caught mistakes long before deployment.

## Component Library & Automated Block Previews

We originally tried [Storybook](https://storybook-astro.org/), but it felt overly complex for our Astro setup. Instead, we built a lightweight, Astro-native styleguide (~500 lines of code) gated behind a build flag so zero bytes ship to production. Every story is a real Astro route rendered inside a canvas iframe.

Then we turned it into an editorial tool.

**We connected the styleguide directly to the DatoCMS editor.** A simple build script renders every component block, captures a screenshot via Playwright, uploads it to DatoCMS, and sets it as the block's visual preview image.

When editors add a section, they don't guess between names like `ContentMediaSection`. They pick visually from real images of live components.

## Five Custom Extensions, One Clean Plugin

Rather than managing multiple webhooks, a single DatoCMS plugin handles all our custom field extensions:

**Anchor picker:** Pick an anchor on the target page instead of typing "#section-3" and hoping

**Hotspot canvas:** Place image markers by clicking on the image itself

**Job picker:** Choose a live job ad from the ATS — the matching PDFs are uploaded separately

**Filter picker:** Link to a pre-filtered listing (e.g. all references in one industry)

**Advanced toggle:** An "advanced settings" group inside blocks, where fieldsets aren't available

## AI-Assisted Content Workflows: What Worked (and What Didn't)

We tested three different approaches to AI content management:

### Attempt 1: Guided Editorial Assistant (Official DatoCMS MCP)

We configured an assistant for the client's editors with two core tasks: *create a reference* and *build a page*. It guides editors through structured questions, enforcing field rules and fetching existing taxonomy tags without inventing new ones.

*Verdict:* **Works great for one-off manual tasks**, like turning a raw Word document into a formatted reference page.

### Attempt 2: Custom Editorial MCP Server

For bulk data work, the official API felt slow. We built a custom Cloudflare Worker server to stream local edits.

*Verdict:* **A detour.** Even a faster API server still suffers from network round-trips and lacks instant local diffing. We archived the branch and moved on.

### Attempt 3: Local File Mirroring (The Winner)

We created [`@heartidentity/datoeditsync`](https://www.npmjs.com/package/@heartidentity/datoeditsync) to pull the entire DatoCMS project down into **local JSON files**: content, schema, and media metadata. DatoCMS is genuinely fast when you fetch everything at once, so the initial pull is one upfront cost. From there the agent uses ordinary file tools: read, edit, grep. No round-trip per field, full-text search across every record in every language, arbitrarily large changes in one pass.

Writing back is modelled on git:

-   **Three-way merge** — base, local, remote. Only changed fields are written, with the record's version as an optimistic lock, so a colleague editing other fields of the same record loses nothing.
-   **Push is a dry run by default.** You see the diff before anything is written.
    
-   **Real conflicts** — same field, same locale, both sides changed — are skipped and reported with all three versions. In practice the agent stops and asks.
-   **Writes land as drafts.** Publishing is a separate, explicit step.
    
-   **The media library is part of the mirror.** Alt text and titles live on the upload, not the record. Without mirroring them, a translation pass sees no captions at all — and the first sign is German alt text on the English site.
    

Setup is one command that generates a project-specific agent skill from the live schema. It carries a provenance stamp and warns when it has drifted, because that skill is the contract the agent acts on — and stale instructions make an agent confidently wrong.

**What that looked like in practice.** Three real instructions:

> "Here's a spreadsheet with all our project references. Enter them."

> "I got a correction for this reference — bring it up to date."

> "German is done. Now translate everything into English and French."

The last one was given the day before launch. **Three hours later the entire site existed in three languages** — 72 pages, 222 references, every product, every UI string, in DatoCMS as drafts. Through an MCP that would have been a multi-day job.

Two qualifications. German is the primary language; English and French are a clear second priority, and two native speakers at Erich Keller are proofreading them where it matters. To make that reviewable by people who don't work in a CMS, we exported the translations to a Google Sheet. Corrections get read back out of the same sheet and written into DatoCMS. And we don't know whether a file mirror is the best abstraction for agent-driven CMS work. It worked remarkably well.

## Beyond the Website: What Else DatoCMS Powers

-   **Dynamic Slide-Deck Configurator:** Sales reps build custom pitch decks using CMS project data. Decks render via Astro components and export to pixel-perfect PowerPoint or PDF files. (Yes, it's images on purpose ;-)
-   **ATS-Driven Job Boards:** Openings sync statically from an [external ATS](https://www.dualoo.com/de/). If the ATS API goes down during a build, the system gracefully falls back to the previous deployment's snapshot.
    
-   **Context-Aware HubSpot Forms:** Embedded natively (no slow iframes) with visual styling matching our design tokens, pre-filling query parameters and form fields automatically.
-   **3D Product Configurator Leads:** The Talky 3D room-in-room tool captures customized specs, passes them to a native hubspot form, and attaches configurations directly to new sales leads.
    

## Lessons Learned

-   **Fewer page models, more blocks:** One flexible tree-based page model and a robust block library gave our editors complete freedom without requiring developer intervention.
-   **Store schemas in Git:** Keeping models in code makes them instantly readable and type-safe for both human developers and AI assistants.
    
-   **Show visual previews to editors:** Replacing text-only block names with auto-generated component screenshots transformed how intuitive the CMS feels to content creators.
-   **For heavy bulk edits, mirror content locally:** Working against local files eliminates API latency bottlenecks when performing massive data operations.
    
-   **Keep human oversight where it matters:** AI accelerated code generation and translation passes dramatically, but custom 3D animations, artwork, and design nuance still rely entirely on human craftsmanship. And we could probably fill a book with our prompts 😀
    

## Credits

**Creative Direction:** Michael Hinderling  
**Project Lead & Editorial:** Katrin Park  
**Experience Design:** Milo Peter  
**3D & Motion Design:** Dario Linke  
**Wireframe & IA:** Dan Nessler  
**Tech Direction & Architecture:** Severin Klaus