/projekte/next-cms/Fullstack/Live/03/2025 → 12/2025/Alleinentwickler

NextCMS

CMS-Vorlage für Kundenprojekte: Page Builder, Admin-Dashboard und zwölf zuschaltbare Module — klonen, Module wählen, Inhalte pflegen.

Der Kern entstand in mehreren aufeinander aufbauenden Kundenprojekten und wurde 2026 zu einer generischen Vorlage zurückgebaut. Sie ist heute der Ausgangspunkt für neue Kundenwebsites.

Privates Projekt

Repository ist privat — Code zeige ich auf Nachfrage.

Keine öffentliche Demo — die Vorlage läuft immer als konkretes Kundenprojekt unter eigener Domain.

project dossier

Snapshot

next-cms

Alleinentwickler

category

Fullstack

status

LIVE

stack

12 tech

code

108.516 Zeilen
Next.jsTypeScriptReactDrizzle ORMPostgreSQLbetter-authMinIO
01

Zahlen zum Projekt

Code108.000Zeilen in 665 Dateien
Seitenrouten110Next.js-Seiten
API-Routen80Route Handler
Zuschaltbare Module12Blog, Shop, Termine …
Komponenten200TSX-Dateien
02

Story

Problem

Jedes Kundenprojekt brauchte ein eigenes Redaktionssystem; fertige CMS waren entweder zu schwer oder nur gehostet nutzbar.

Lösung

Headless CMS auf Next.js mit eigenem Admin-Interface, rollenbasierten Rechten über Row-Level-Security und einem Auto-Install-Skript für Docker-Hosts.

Learnings

Der Aufwand lag nicht im Editor, sondern in Installation, Migrationen und Environment-Handling.

03

Key Features

features.md
  • →Installationsskript bringt eine Instanz in unter 10 Minuten online
  • →Rechte über Row-Level-Security in der Datenbank statt nur in der Anwendung
  • →Frei definierbare Inhaltstypen für Seiten und Sammlungen
  • →Self-Hosting mit Docker und Nginx
04

Über das Projekt

README.md

Headless CMS auf Next.js mit eigenem Redaktionsbereich, rollenbasierten Rechten über Row-Level-Security und einem Installationsskript für Docker-Hosts. Läuft self-hosted hinter Nginx, Konfiguration und Migrationen sind versioniert.

05

Meine Rolle

rolle
rolle:Alleinentwickler
  • Herauslösen des generischen Kerns aus mehreren Kundenprojekten
  • Modulsystem mit erzwungenen Abhängigkeiten und Build-Prüfung
  • Page Builder und Admin-Dashboard
  • Setup-Ablauf: Schema, Seed und Speicher-Buckets per Skript
  • Dokumentation je Admin-Route direkt neben dem Code
06

Architektur

architecture.md

Zwei Ebenen, und die Trennung ist nicht kosmetisch: im Repo-Root liegt die Infrastruktur (docker-compose.yml, eine einzige .env), darunter in frontend/ die Anwendung. Die .env muss neben Compose liegen, weil Compose ${POSTGRES_PORT} und die Zugangsdaten nur aus einer Datei neben sich auflöst; frontend/.env ist ein Symlink darauf. Zwei getrennte Dateien wären zwei Wahrheiten — und die erste Folge davon ist eine DATABASE_URL, die auf einen anderen Port zeigt als den, den Postgres veröffentlicht.

Die Anwendung ist ein Next.js-Projekt mit drei Routenbereichen: (landing) für die öffentliche Website, (default) für angemeldete Nutzer und (admin) für die Redaktion. Dazu ein /setup-Pfad für die Erstinstallation.

Der Kern ist das Modulsystem. Zwölf Funktionsbereiche — Blog, Testimonials, Termine, Events, Quiz, Newsletter, Shop, Kunden, Schnittstellen, QR-Codes, Analyse, Bug Tracker — lassen sich einzeln zuschalten. Ein Modul ist an genau einer Stelle definiert: Beschriftung, Beschreibung, Voreinstellung, betroffene Menüpunkte und Abhängigkeiten stehen in einem Objekt, alles andere wird daraus abgeleitet. Abgeschaltete Bereiche antworten mit 404 und verschwinden aus Menü und Sitemap.

Wichtig dabei: ein Modulschalter räumt die Oberfläche auf, er ist keine Sicherheitsgrenze. Der Admin-Guard läuft davor, und ein Admin kann jeden Schalter ohnehin umlegen.

Jede Admin-Route trägt neben ihrer page.tsx eine eigene doc.md mit Datenfluss, Berechtigungen und Fallstricken für genau diesen Bildschirm — gelesen im Editor, nicht ausgeliefert.

Page Builder

Seiten aus Bausteinen, deren Eigenschaften aus der Datenbank kommen — neue Seiten ohne Codeänderung.

Next.jsDrizzle ORM

Modulsystem

Zwölf zuschaltbare Bereiche mit erzwungenen Abhängigkeiten und vier Voreinstellungen (Website, Website + Shop, Betrieb, Minimal). Eine Prüfung im Build hält Registry und Oberfläche zusammen.

TypeScript

Admin-Dashboard

Nutzer, Kontakt, Blog, Medien, SEO, Termine, Rechtstexte — plus eine handgeschriebene Hilfeseite für Endnutzer.

shadcn/uiRadix UI

Auth und Datenschicht

better-auth auf PostgreSQL mit Drizzle ORM, Schema und Seed über Skripte statt über Handarbeit.

better-authDrizzle ORMPostgreSQL

Medienspeicher

MinIO als S3-kompatibler Speicher, Buckets werden beim Setup angelegt.

MinIODocker

Schnittstellen

REST-Endpunkte und ein MCP-Zugang, damit Inhalte auch von außerhalb der Oberfläche gepflegt werden können.

MCPTypeScript
07

Herausforderungen

Ein Modul, drei Listen
Problem

Schlüssel, Voreinstellungen, Menüzuordnung und die Beschreibung in den Einstellungen standen in drei getrennten Listen. Ein neues Modul musste überall eingetragen werden, und nichts erzwang, dass die Listen zusammenpassen — fehlte der Eintrag in der Oberfläche, existierte das Modul, war aber nicht schaltbar.

Lösung

Eine Registry als einzige Definitionsstelle; alles andere wird abgeleitet. Abhängigkeiten werden erzwungen, nicht nur angezeigt, und eine Prüfung im Build stellt sicher, dass jeder Verweis auf ein existierendes Modul zeigt und die Kette zyklenfrei bleibt. Icon und Farbe haben einen Fallback, damit ein Modul nicht durch ein fehlendes Symbol verschwindet.

Marken- und Branchenreste beim Zurückbauen
Problem

Der Code kam aus konkreten Kundenprojekten. Beim Rückbau auf einen generischen Kern bleiben Reste hängen — in Routen, Seed-Daten, Übersetzungen, Assets — und die fällt erst dem nächsten Kunden auf.

Lösung

Ein Prüfschritt `check brand` sucht Marken-, Branchen- und Amtsvokabular über den gesamten Bestand. Dazu die Regel im Repository: Stößt man auf Inhalt, der eine bestimmte Branche oder eine reale Person voraussetzt, ist das ein Rest und kein Feature.

npm würde die Sicherheits-Pins still übergehen
Problem

Die Versions-Pins und die Allowlist für Post-Install-Skripte stehen unter package.json-Schlüsseln, die npm kommentarlos ignoriert. Ein `npm install` hätte einen ungepinnten Abhängigkeitsbaum aufgelöst — ohne Warnung.

Lösung

Ein preinstall-Wachhund weist npm und yarn mit einer Erklärung ab. Installiert wird ausschließlich mit pnpm; die Skript-Kurzformen funktionieren weiterhin mit beiden.

08

Technologie-Entscheidungen

09

Codebasis

codebase
Codezeilen108.516
Dateien665
Sprachen
  • TypeScript/TSX98%
  • SQL2%
10

Verwandte Projekte