From-Scratch Build · Backend
The content engine behind a lab website — a headless CMS that stores every page, person and post in a database and serves it to a frontend over a REST API. Rebuilt from scratch to learn how a content backend models, secures and delivers data without rendering a single page itself.
What it is
This is the half of the system that visitors never see. It renders nothing. Its entire job is to be a content backend: a place where editors define content types, fill them with data, and expose that data as a clean API for a separate frontend to consume.
I built it to learn the headless CMS pattern. Instead of writing models, an admin and an API by hand, a headless CMS gives you all three from a content schema you design in its dashboard — and then hands every editor a polished interface and every developer a typed REST endpoint.
The core idea I wanted to learn: content is a service. When the backend's only deliverable is well-structured JSON over an API, any number of frontends — a website, a mobile app, a screen in a lobby — can all draw from the same single source of truth.
The stack
The point of this rebuild was the toolchain. Here is what each piece actually does in the system.
A Node.js content platform that turns a schema into a database, an admin dashboard and a REST API — all generated, not hand-written.
The server, database and API are configured in typed config files, so settings are checked and self-documenting.
Each content type — page, person, post — is defined as a schema; the CMS builds the table and the edit forms around it.
Every content type is exposed as an endpoint that returns JSON, protected by API keys and role-based permissions.
A managed uploads folder stores images and files, served back to the frontend by URL.
Separate dev and production Dockerfiles package the CMS and its database so deployments are reproducible.
Architecture
A piece of content travels the same path from definition to delivery. Tracing it made the headless model click.
In the dashboard you describe the fields of a "page" or "person"; the CMS scaffolds the database table.
Editors fill in content through generated forms — no code, no database access required.
Entries are persisted with their relations and uploaded media tracked alongside.
Roles and API tokens decide which content types are public and which require a key.
A frontend requests an endpoint and receives the content as structured JSON.
The whole CMS plus database ships via Docker for a consistent production environment.
How it runs
Standing the backend up is about preparing its environment and letting the CMS take over:
.env.example and set the database connection and secret keys.docker compose up starts the CMS, its database and the admin dashboard.In my rebuild I focused on the content schema and the permissions layer — the two things that decide what the frontend is allowed to ask for.
Reflection
.env files are what let the same CMS run safely in development and in production.