Kunal Chaudhari
Open to work Let's talk

(Corporate CMS) Jun 2025 — Dec 2025 · Webbrains Technologies

DemandTrans

One system for every page and product, with every edit checked and recorded.

A content system for a corporate website and product catalogue. Every edit is checked and recorded, and the whole system is packaged to run the same way on any server.

Role
Full Stack Developer
Focus
Shared middleware, containerisation
Status
Delivered, Dec 2025

(01) In numbers

  • 7Months, June to December

    From first schema to handover

  • 2Shared middleware layers

    Validation and audit, ahead of every handler

  • E2EContainerised

    The same image locally and in production

(02) Under the hood

Every write passes the same two questions

  1. 01 · EDITOR

    Content request

    Someone changes a page. Before any of it reaches the database, the same questions get asked that every other content type asks.

  2. 02 · VALIDATE

    Schema check

    Payload shape, required fields and types are settled in middleware. A controller that runs has already been handed something it can trust.

  3. 03 · AUTHORISE

    Permission gate

    Who is allowed to edit this type, in this section. The check sits in front of the route rather than inside it.

  4. 04 · AUDIT

    Change record

    Who changed what, and when — written by the shared layer, so no content type has to remember to do it.

  5. 05 · SERVICE

    Content module

    The part that is actually specific to this content type. By this point it is only the part that is specific.

  6. 06 · DATA

    MongoDB

    Mongoose models per content type, sharing the same base fields and the same audit shape.

  7. 07 · SHIP

    Docker Compose

    The service, its database and its proxy described in one file. What runs on a laptop is what runs on the server.

(03) The story

01 — The Problem

The same checks, on every content type

A corporate CMS grows content types faster than it grows anything else. Each new one needs its payload validated, its editor authorised and its change recorded — and written per type, those become dozens of nearly identical blocks that drift apart quietly.

  • Many content types, one set of rules about writing.
  • A change record that no route is allowed to skip.
  • The same behaviour on a laptop as on the server.

02 — What I Built

Two layers everything passes through

Validation and audit were pulled out into middleware that every route mounts. A content module is then only the logic that makes it different, and the whole service is described in Compose so the environment stops being a variable.

  • Reusable validation middleware, applied before any handler runs.
  • Reusable audit middleware, recording who changed what on every mutation.
  • Express modules per content type over Mongoose models with a shared base.
  • Docker Compose, from local development through to the deployed server.

03 — What Changed

A new content type is a route file

The rules arrive with the mounting rather than with the author's memory. And because the container is the unit of delivery, works-on-my-machine stopped being a category of bug.

  • New modules inherit validation and audit by being mounted.
  • Change history has the same shape across every content type.
  • Local and production run the same image.

(04) Architecture

Shared layers, then the part that differs

  1. 01

    Editors

    The admin surface the content team works in.

  2. 02

    Edge

    Nginx and PM2 in front of the Node service, with SSL.

  3. 03

    Middleware

    Validation and audit: the two layers every route shares.

  4. 04

    API

    Express modules, one per content type, mounted behind the shared layers.

  5. 05

    Data

    Mongoose models with a common base and a common audit shape.

  6. 06

    Containers

    Docker Compose describing the service, the database and the proxy together.

(05) Decisions

Why it is built this way

  1. (01)

    Shared behaviour belongs in front of the route

    Validation and audit are things every mutation needs, so they are mounted rather than called. Did this route remember? becomes a structural question instead of a review comment.

  2. (02)

    One base shape for every content type

    Content types differ in their fields, not in how they are created, changed and recorded. Sharing that base is what makes a new type cheap to add.

  3. (03)

    Containerise the whole thing, not just the app

    Compose describes the service together with its database and its proxy. The environment stops being something that has to be rebuilt by hand and remembered correctly.

(06) Built with

What it runs on

Written once, mounted everywhere, shipped as an image.

For the technically curiousReusable audit and validation middleware, containerised end to end. A corporate content platform with many content types, each one needing the same things before it writes: a validated payload, a permission that holds, and a record of who changed what. Those became two middleware layers every route shares, and the whole service runs in containers from a laptop through to production.

Node.jsExpressMongoDBMongooseReactDockerComposeNginxPM2JWTWinston