DEV Community

Oleg Jakunin
Oleg Jakunin

Posted on

I built OJ CMS because the editor should not have to understand my website

Developer assembling the OJ CMS interface on a Payload engine

Open a CMS. Find the right section. Figure out which field actually appears on the page. Hope changing it does not disturb the layout.

That is a lot of background knowledge for someone who wants to update a product description.

When I built OJ CMS, I wanted to remove that background knowledge from the job. The editor should recognize the content and know what happens after saving it. The way I assemble the website should mostly be my problem.

OJ CMS is my custom administration interface on top of Payload. The public site uses Next.js and React. Content, inquiries and selected traffic information can live in the same workspace, with the interface adapted to the project.

The WordPress habit I wanted to break

I do not like starting a custom website by searching for a theme and then searching for plugins to repair the mismatch.

A catalog needs documents connected to products. A product needs specifications. An editor needs to know whether a record is published. None of that starts as a theme decision.

Yet it is easy to make the theme the center of the project. Then the business gets expressed through whatever the theme and its extensions happen to support. A requirement becomes a search for another plugin. A design change becomes an exception to someone else's layout system.

That is the default I wanted to leave behind. I want to decide what the site does, model its content and build its interface around that.

Writing your own software does not mean writing every layer

I did not write a new authentication system to prove that I am a developer. I did not invent a database abstraction for the same reason.

Payload provides the CMS foundation. I use it to describe content and build the behavior around it. OJ CMS is the layer where I make the editor experience specific.

Think about attaching a document to a product. That relationship should be part of the content model. The editor can select the document, and the website knows where to show it. Nobody needs to remember which text block contains the download link.

That sounds mundane. Good. Updating a catalog should be mundane.

The small decisions matter more than the dashboard screenshot

A dashboard can look impressive while telling you very little about what to do next.

I care more about whether an editor can find the record they just changed. Whether the interface makes a draft obvious. Whether leaving a page with unsaved changes feels different from leaving a saved page. Whether a media item already used by the website can be mistaken for something disposable.

Incoming inquiries belong close to the content that prompted them. Traffic information is useful when it helps someone decide what to update, rather than turning the admin into a wall of charts.

The design work is partly about removing irrelevant choices. An editor managing news and products does not need a miniature tour of my technology stack every morning.

A custom frontend gives me somewhere to put responsibility

I want control over the public website too. Its layout, interaction and mobile behavior should follow the project, not the limitations of a purchased theme.

With structured content, I can change how a product page renders without rebuilding its content. The same data can support a category listing, a detail page and a search result. An editor does not have to create three versions of the same information.

There is also less room to dodge the engineering work. If I ship oversized images or unnecessary JavaScript, that is mine to fix. If publishing does not update the website correctly, I need to fix that path. Installing a modern framework does not excuse any of those things.

That accountability is part of why I prefer this approach.

OJ CMS responsibility map: custom interface, server access checks, Payload, website, database and external analytics

The custom screen still needs real permissions

One detail for anyone trying this with Payload: the Local API overrides access control by default. A custom server operation acting for an editor needs to opt into the access checks and pass the authenticated user.

Hiding an action in React is not permission enforcement. The server still has to decide whether the user can perform it. Payload documents the Local API options here.

This is the kind of complexity worth keeping in the code, rather than pushing into an editor's daily work.

What about EmDash?

EmDash is worth a look if you are exploring an Astro-based CMS. It offers another route into modern TypeScript publishing, including sandboxed plugins.

OJ CMS uses Payload. I am interested in EmDash because it asks some of the same underlying questions about how a CMS and its extensions should be put together. I would compare the editorial workflow and deployment requirements before picking a foundation for a new project.

Start with the thing your editor is trying to do

I am not interested in rebuilding familiar CMS features just to put my name on them. I am interested in the awkward gap between a generic admin and a particular website.

For OJ CMS, that meant treating products, documents, news and inquiries as things the interface understands. It meant keeping the public design independent of the editor. It also meant accepting that a custom interface is software I have to maintain.

The question I would ask before adding another plugin is: are we implementing the actual task, or teaching someone another workaround?

Which part of your current CMS makes editors learn something they should not need to know?


Writing and illustrations prepared with AI assistance.

Top comments (0)