FountainCMS is a headless, data-first Content Management System designed to manage structured content, datasets, and metadata in a clean, scalable, and developer-friendly way.
This repository is organized as a monorepo containing both the frontend (React) and backend (NestJS) codebases that together power the FountainCMS ecosystem.
FountainCMS focuses on explicit content modeling and API-first delivery.
Instead of tightly coupling content with presentation, it treats content as structured data, allowing teams to:
- Define clear schemas for content and datasets
- Validate and manage data centrally
- Serve content securely through APIs
- Power multiple frontends from a single backend
It is built for teams that care about data quality, strong contracts, and long-term maintainability.
Most CMS platforms are either:
- Too rigid for real-world, evolving data models
- Too abstract, hiding important data decisions behind UI layers
FountainCMS solves this by:
- Making schemas explicit and versionable
- Encouraging clean separation of concerns
- Prioritizing developer control and predictability
This makes it especially useful for data-heavy products, dashboards, internal tools, and modern web applications.
- Developers who want full control over content modeling
- Backend-first or API-driven teams
- Startups looking for a flexible, open CMS
- Teams managing datasets, metadata, or configuration-heavy content
fountaincms/
βββ frontend/ # React + Vite frontend app
β βββ src/
β βββ public/
β βββ vite.config.ts
β βββ index.html
β βββ package.json
β βββ tsconfig.json
βββ backend/ # NestJS backend (TypeScript)
β βββ src/
β β βββ content/
β β βββ roles/
β β βββ user/
β β βββ ...
β βββ test/
β βββ package.json
β βββ tsconfig.json
β βββ jest.config.js
β βββ README.md
βββ package.json # Monorepo root (workspaces)
βββ .gitmessage # Conventional Commits template
βββ .husky/ # Git hooks (commit-msg, pre-commit)
βββ lint-staged.config.js
βββ commitlint.config.js
βββ SECURITY.md
βββ CONTRIBUTING.md
βββ .github/ # Issue/PR templates, workflows
βββ .nvmrc # Node.js version for development (v22.13.1)
βββ README.md
A. System Architecture Diagram This diagram shows the physical flow of the monorepo components.
graph LR
subgraph Client
A[React Frontend <br/> Vite]
end
subgraph Server
B[NestJS Backend <br/> REST API]
end
subgraph Database
C[Prisma ORM]
D[(PostgreSQL)]
end
A <-->|HTTP/JSON| B
B <--> C
C <--> D
B. Content Modeling Workflow A sequence diagram showing the "data-first" lifecycle of a single request.
sequenceDiagram
participant FE as Frontend (React)
participant CN as NestJS Controller
participant SR as Service Logic
participant PR as Prisma Client
participant DB as Database (PostgreSQL)
FE->>CN: GET /api/content/:id
CN->>SR: Request Data Validation
SR->>PR: Query Execution
PR->>DB: SQL Select
DB-->>PR: Raw Data
PR-->>SR: Typed Object
SR-->>CN: Processed Content
CN-->>FE: JSON Response
C. Modular Backend Structure
A flowchart to help contributors navigate the backend/src directory logic.
graph TD
Root[backend/src] --> Auth[Auth Module]
Root --> Content[Content Module]
Root --> User[User Module]
Root --> Roles[Roles Module]
Content --> C_Ctrl[Controllers]
Content --> C_Srv[Services]
Content --> C_Ent[Entities/DTOs]
Auth -.->|Guards| Content
Roles -.->|Permissions| Content
- Node.js (v22.13.1 required, see
.nvmrc) - npm (v7+ recommended for workspaces)
At the root of the repository:
npm installThis installs dependencies for both frontend and backend using npm workspaces.
Open psql as postgres superuser:
sudo -u postgres psqlCREATE USER fountain_user WITH PASSWORD 'fountain_pass';
CREATE DATABASE fountain_db OWNER fountain_user;
ALTER USER fountain_user CREATEDB; -- required for Prisma migrate dev
\qcd frontend
nano .envCopy the details from .env.sample to .env and save
cd backend
nano .envCopy the details from .env.sample to .env and save
Auth is configurable via AUTH_MODE in backend .env:
AUTH_MODE=local(default): Email/username + password. Users need apasswordHashin the DB (see seed).AUTH_MODE=oauth2: OAuth 2 / OIDC. SetOAUTH2_ISSUER,OAUTH2_CLIENT_ID,OAUTH2_CLIENT_SECRET, and optionally claim mapping. Login redirects to your IdP, then callback sets a JWT cookie.AUTH_MODE=saml: SAML 2.0. SetSAML_ENTRY_POINT,SAML_IDP_CERT,SAML_ACS_URL, and optionally attribute mapping.
JWT is issued after any successful login (local or SSO) and sent in an HttpOnly cookie; the frontend also supports Bearer token for API clients. See backend/.env.sample for all auth-related variables.
cd backend
npx prisma migrate dev --name initThis will:
- Create DB tables
- Generate Prisma Client
- Sync schema
sudo apt update
sudo apt install docker.io docker-compose-pluginsudo systemctl start docker
sudo systemctl enable dockerFrom the project root directory:
docker compose up -d dbEnsure your backend/.env contains:
DATABASE_URL=postgresql://fountain_user:fountain_pass@localhost:5432/fountain_db?schema=publicAfter the database container starts:
cd backend
npx prisma migrate dev --name initTo start backend and database together:
docker compose up --buildThis will:
- Start PostgreSQL
- Build and run backend service
- Expose backend at:
http://localhost:4000
npm run devStarts both services in parallel using concurrently.
npm run dev:frontendnpm run dev:backendOnce the backend is running:
http://localhost:4000/api-docs
-
Linting and formatting are enforced via Husky and lint-staged
-
Run all tests:
npm test -
Pre-commit hooks will block commits if checks fail
This project follows Conventional Commits.
git config --local commit.template .gitmessage- Follows Keep a Changelog
- Uses Semantic Versioning
-
Update
CHANGELOG.md -
Commit:
git commit -m "chore(release): update changelog for vX.Y.Z" -
Tag and push:
git tag vX.Y.Z git push origin vX.Y.Z --follow-tags
- See CONTRIBUTING.md
- See SECURITY.md
The backend has been migrated from Express to NestJS for:
- Better scalability and modularity
- Improved type safety
- Cleaner architecture
We welcome contributors of all experience levels:
- Build features and integrations
- Fix bugs
- Improve docs and DX
- Review and test code
π Check: