Case study · Orange Polska
A CMS the backend can extend without frontend changes
How I designed a schema-driven CMS at Orange Polska in front of a growing set of legacy systems, and what it cost and gained.
Outcome
Dozens
of new resources in production without frontend work
- My role
- I chose the stack and designed the frontend architecture
- When
- Since late 2022
- Team
- 5 developers (including me), 3 testers, 1 product manager
- Stack
- React, TypeScript, MUI, JSON Schema, React JSON Schema Form (RJSF)
The situation
Orange Polska needed one internal CMS to sit in front of a growing number of legacy systems and services, each built differently. It had to stay stable and maintainable for years. There was no fixed specification: new requirements, features and integrations would keep arriving as the project went on.
Constraints
- A small team that, at the start, knew vanilla JavaScript but not a frontend framework.
- Legacy systems with their own rules, and a lot of customisation expected on top.
- A stack that would not lock us in. It had to be mature enough to rely on for years, flexible enough for heavy customisation, and not so strict or unusual that new people would struggle to learn it.
Options I considered
The decision
The biggest decision was how much control to give the backend. We let the backend describe the frontend: navigation, URLs, views and forms all come from backend configuration and JSON Schema. The React app is a generic renderer for whatever the backend sends.
The trade-off was debugging. When something goes wrong, the cause can sit in configuration far from the screen that shows the problem. We answered this with:
- Error logging designed for this setup.
- A strict frontend/backend contract checker. It checks what the backend sends against what the frontend expects, and logs detailed errors to the console for developers.
- Friendly messages for users: a short notification explaining that something went wrong, instead of a broken screen.
How it works
- BackendSends configuration and JSON Schemas
- CMS shellBuilds navigation, URLs and views from the configuration
- FormsRJSF renders the schemas with our custom fields and widgets on MUI
- Data gridsMUI X Data Grid shows data with configured actions, including bulk operations
The outcome
The frontend stays out of the way. When a new resource is added, the backend usually configures it fully and it works in the frontend without changes. Dozens of new resources have reached production without any frontend work.
What I'd do differently
I'd be stricter about customisation. Some features we rebuilt were already working in MUI or RJSF. For example, the business asked us to override default hover and keyboard behaviour. Each override is code we now maintain, and changing standard keyboard behaviour also makes an interface harder to use with a keyboard or a screen reader. I would push back on requests like that earlier.