All articles
13 · Engineering · 2026.09 · 5 min

One platform, many sites: the content model in a multilingual CMS

YEE CMS is a multisite, multilingual platform built to manage the content of Yunus Emre Institute's different centers on a shared foundation. In this article I explain why the content model sits at the center of a system like this, and how I think about the relationship between its layers.

01Shared foundation, separate publishing spaces

On paper the problem looks simple: bring the content production, permissions and publishing flow of different centers into one system. The hard part is that every site has to keep its own context while doing so. An editor at one center should see only their own site, languages and approval process, and a visitor should only meet that site's content. This balance between a shared foundation and separate publishing spaces is the real design question, and it runs through every layer.

At first glance the two needs pull against each other. Sharing means maintenance, updates and new capabilities reach every site at once. Separation means each center can publish in its own languages, with its own editors and on its own schedule. In systems like this, the first thing I try to do is separate clearly which decisions are common to everyone and which belong to a single site. If that line is blurry, over time you either write a special exception for every site, or the shared structure forces one site's needs onto another.

02Three layers, one data model

The system has three parts: a public Next.js web front end, an API written in NestJS and an administration app built with React. All three meet on PostgreSQL, with Drizzle ORM and Docker also part of the stack. This split lets the editor experience and the visitor experience evolve independently. But because they rest on the same content model, both have to follow the same rules.

layers
web    Next.js     → the page a visitor sees
admin  React       → an editor's daily work
api    NestJS      → site context, language, approval
db     PostgreSQL  (Drizzle ORM)

The layers also have different priorities. On the public web side, the priority is that a page opens quickly, arrives in the right language and is understandable to search engines. On the administration side, the priority is that editors can work comfortably with forms, drafts and approval steps. The API sits between these two worlds like a referee: it decides which site, language and permission a request belongs to. For me, the most valuable part of this structure is that the rules live in one place, and the interfaces show their results instead of rewriting them.

A tool like Docker makes it easier for these layers to come up the same way in different environments. In a system with many parts, that consistency helps reduce the differences between development and production.

03A content model is more than a schema

Multilingual content, site context and content approval flows are core parts of this product. Which site a piece of content belongs to, which languages it exists in and which steps it passes before going live shape the screens in the administration panel and the pages on the web as much as the tables in the database.

So when I talk about the content model, I am not only thinking about fields and relations. Is a field required, is it translatable, can it be shared across sites: each of these questions turns into a behavior on the editor's screen and a result on the visitor's page. Anything left vague in the model usually comes back as confusion in the interface. In a multisite structure, I find it safer to treat site context not as a filter added later, but as basic information every request carries from the start.

A content model designs the editor's day and the visitor's page together.

04Language and approval: two separate axes

A common trap in multilingual systems is to think of a translation as a simple copy of the content. In reality, the versions of the same content in different languages can be prepared at different times, pass through different hands and sit at different stages. In structures like this, it feels healthier to me to treat language and publishing status as two independent axes. That way, one language version being live while another is still in preparation is not an exception, but a natural state of the model.

The approval flow deserves the same thinking. Whether content is a draft, in review or published is not just a piece of status information; it also decides who can see what and who can change what. When permissions and workflow are this closely linked, treating them as parts of the same model rather than designing them separately makes consistency easier to keep.

05Where I fit in

YEE CMS is a Unitic project and a team effort. My part is full-stack development and integration: front end, services, content management flows and making the layers work together. Integration work shows me, more than anything, how a decision made in one layer finds its counterpart in the others. In this work I focus on how the content model shapes not only the database, but also an editor's daily work and the page a visitor sees.

Working in a team, the answers to these questions take shape in shared decisions rather than in one person. My share is to help those decisions find the same expression in the interface, the services and the data.

Related articles
  1. 14One product, three surfaces: web, service and mobile in one monorepoEngineering2026.085 min
  2. 15Blockchain on real devices: 72 hours with three Raspberry PisR&D and hardware2026.075 min