Skip to content
← All work

01 · Headless CMS & agency platform

Deltaweb CMS

One content panel for every client site, with an AI assistant built in.

Every client site at Deltaweb used to need its own way of editing content. Deltaweb CMS is the answer: a headless, multilingual, mobile-friendly admin panel that installs into any Next.js site. The CMS only supplies content; the design always stays in the site's own components.

A single command line tool installs it into a client project with a package preset, languages and brand colour, checks the setup, and later shows and applies updates. A central hub, Deltaweb Merkez, keeps track of every installed site, compares versions and opens a pull request in the site's repository when a new release is out.

Inside the panel there are fifteen content modules — pages, blog, news, products, services, FAQ, documents, dealers and more — plus approvals, an inbox with outbound email, a content calendar, a team board, roles and invitations, and search across everything. AI is part of the workflow rather than a bolt-on: content plans, drafts, adaptation into other languages, refreshing ageing pages and reply drafts can each be routed to the built-in assistant or to Claude over MCP, or switched off.

It is the codebase I hold to the strictest standard: plain-language Turkish and English interface, WCAG 2.2 AA, permission checks and activity logging on every server action, and several hundred unit, integration and end-to-end test files.

Year
2026
Role
Architecture, full stack, product
Stack
Next.js 16, React 19, TypeScript, PostgreSQL, Drizzle ORM, Better Auth, Vercel AI SDK, MCP, Tiptap, Tailwind CSS 4, Vitest, Playwright
Languages
  • TypeScript97.9%
  • JavaScript1.6%
  • Other0.5%
Links

Private repository

From the repository

Content modules
15
Database tables
50
Migrations
34
Test files
368

Technical architecture

One Next.js codebase that is both the CMS source and its demo site. Installed into a client project, it adds an admin panel and a content API; the site keeps rendering everything with its own components.

  1. L1

    Client site

    • cms.* API
    • <CmsContent>
    • GET /api/cms/content
    • cms.config.ts

    Reads content through a typed API or a read-only JSON endpoint; pages, menus and forms are drawn by the site itself.

  2. L2

    Admin panel

    • Next.js 16
    • React 19
    • Tiptap editor
    • Radix UI
    • Tailwind CSS 4
    • ⌘K search

    Block-based editing, approvals, inbox, content calendar, team board, users and roles — in Turkish and English.

  3. L3

    AI

    • Vercel AI SDK
    • Anthropic · OpenAI · Google
    • MCP server
    • OAuth for MCP clients

    A panel assistant and an MCP server share the same jobs; each job type is routed to one of them, or turned off.

  4. L4

    Core & data

    • Server Actions
    • Better Auth
    • Drizzle ORM
    • PostgreSQL
    • Web Push
    • Nodemailer

    Any PostgreSQL — Neon, Supabase or a local Docker instance; every action checks permissions and writes to the activity log.

  5. L5

    Distribution

    • npx deltaweb-cms
    • init · diff · update · doctor
    • Deltaweb Merkez
    • GitHub Actions

    The CLI installs and updates client sites; the hub tracks their versions and opens update pull requests.

From release to client site

How a new CMS version reaches a site that is already live.

  1. 01

    Release

    The version in package.json is bumped and the changelog gets plain-language notes, including anything the site must change.

  2. 02

    Compare

    Each site records its installed version; Merkez compares it with the latest and lists the notes in between.

  3. 03

    Pull request

    One click runs a workflow in the site's repository that applies the update and opens a pull request.

  4. 04

    Migrate

    After merge, migrations run and the site's own config and custom folder are left untouched.

Engineering decisions

  • Headless on purpose

    Early versions shipped a form designer and site styling. Version 1.0 removed them: the CMS supplies content and the site owns the design, so one panel can serve very different sites.

  • AI routed per job

    Instead of one AI switch, each job type — plans, drafts, translations, refreshes, replies — is assigned to the panel assistant, Claude over MCP, or nobody, and the panel follows that choice everywhere.

  • Provider-independent database

    Drizzle over plain PostgreSQL means a client can run on Neon, Supabase or their own server, each with a separate, fresh database.

  • Tests run locally

    A local CI script spins up its own throwaway Postgres in Docker and runs typecheck, lint, unit, CLI and integration tests, so GitHub Actions minutes are not spent on every push.

Engineering checklist

The questions a reviewer asks, answered from the code — including the ones where the honest answer is no.

Database designIn place
50 tables defined in Drizzle with 34 versioned SQL migrations; any PostgreSQL works.
Authentication & authorizationIn place
Better Auth sessions, roles with a permission check in every server action, single-use email invitations, and OAuth for MCP clients.
API & data securityIn place
A read-only JSON content API for non-Next.js consumers, a form submission endpoint, cron endpoints guarded by a bearer secret, and an MCP endpoint that masks personal data.
PerformancePartly
Search and pagination run on the server; version 1.1.1 fixed a memory overflow when opening the editor on large sites.
Errors & loggingIn place
Every server action writes to an activity log, and settings secrets are encrypted with a per-site key.
TestsIn place
368 test files across Vitest unit and integration projects, Node tests for the CLI, and 20 Playwright end-to-end specs.
Deployment & CI/CDIn place
Client sites run on Vercel or a VPS with cron; Merkez runs on a VPS behind a reverse proxy, with a manual or self-hosted CI workflow.

Next project

Readability.Lib

Long stories, cut into two-minute reads with generated imagery.