Skip to content

Architecture

Stelo CMS employs a modern, scalable architecture built on the T3 stack with a dual-repository approach that separates content management from content presentation.

graph TB
subgraph "Digital Ocean VPS"
subgraph "Coolify PaaS"
CMS[Stelo CMS Backend]
Frontend[Client Frontend]
end
DB[(PostgreSQL Database)]
Storage[Digital Ocean Spaces]
end
Client[Content Editors] --> CMS
Users[End Users] --> Frontend
CMS --> DB
CMS --> Storage
Frontend --> CMS
Frontend --> DB
  1. Separation of Concerns: CMS logic separated from presentation logic
  2. Independent Scaling: Scale admin and public sites differently
  3. Security: Restrict CMS access while keeping frontend public
  4. Flexibility: Multiple frontends can consume the same CMS
  5. Team Workflow: Different teams can work on CMS vs frontend
stelo-cms/
├── prisma/
│ ├── schema.prisma # Database schema
│ ├── migrations/ # Database migrations
│ └── seed.ts # Database seeding
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── api/ # REST API endpoints
│ │ ├── admin/ # CMS interface
│ │ └── trpc/ # tRPC setup
│ ├── components/ # Shared UI components
│ ├── lib/ # Utilities and configurations
│ └── types/ # TypeScript definitions
├── public/ # Static assets
└── docker/ # Deployment configurations
client-frontend/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── [locale]/ # Internationalized routes
│ │ └── api/ # API routes (if needed)
│ ├── components/ # Frontend components
│ ├── lib/ # API clients and utilities
│ └── types/ # TypeScript definitions
├── public/ # Static assets
└── messages/ # i18n message files

Why Next.js?

  • Server-side rendering for SEO
  • App Router for modern routing patterns
  • Built-in optimizations (images, fonts, etc.)
  • Excellent developer experience

Usage in Stelo:

  • CMS: Admin interface with protected routes
  • Frontend: Public-facing website with dynamic content
  • API Routes: RESTful endpoints for external integrations

Why Prisma?

  • Type-safe database queries
  • Database migrations management
  • Excellent TypeScript integration
  • Multiple database support

Schema Design:

model Page {
id String @id @default(cuid())
slug String @unique
title Json # Localized content
content Json # Localized content
published Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

Why tRPC?

  • End-to-end type safety
  • Excellent developer experience
  • Automatic API documentation
  • Built-in validation with Zod

API Structure:

export const appRouter = router({
pages: pagesRouter, // Page management
collections: collectionsRouter, // Dynamic content
globals: globalsRouter, // Site settings
users: usersRouter, // User management
media: mediaRouter, // File uploads
});

Why NextAuth?

  • Multiple authentication providers
  • Built-in session management
  • Security best practices
  • Prisma adapter support

Configuration:

  • Email/password authentication
  • Google OAuth (optional)
  • Role-based access control
  • Session persistence

Why PostgreSQL?

  • ACID compliance
  • JSON support for localized content
  • Excellent performance
  • Wide ecosystem support

Features Used:

  • JSON columns for multilingual content
  • Full-text search capabilities
  • Robust indexing
  • Foreign key constraints
  • Size: 2GB Memory / 50GB Disk
  • Location: LON1 (London)
  • OS: Ubuntu 24.04 LTS x64
  • Purpose: Hosts all application services
  • Role: Platform-as-a-Service for deployment
  • Features:
    • Docker-based deployments
    • Environment management
    • SSL certificate automation
    • Git-based deployments
  • Type: S3-compatible object storage
  • Cost: $5/month base
  • Usage: Media files, backups, static assets
  • CDN: Built-in CDN for global delivery
  • Version: postgres:17-alpine
  • Deployment: Docker container
  • Backups: Automated daily backups
  • Connection: Connection pooling with Prisma
sequenceDiagram
participant Editor as Content Editor
participant CMS as Stelo CMS
participant DB as PostgreSQL
participant Storage as DO Spaces
participant Frontend as Client Site
Editor->>CMS: Create/Edit Content
CMS->>DB: Save Content Data
Editor->>CMS: Upload Media
CMS->>Storage: Store Media Files
CMS->>DB: Save Media References
Frontend->>CMS: Request Content
CMS->>DB: Query Content
CMS->>Frontend: Return Typed Data
sequenceDiagram
participant User as End User
participant Frontend as Client Site
participant API as CMS API
participant DB as Database
User->>Frontend: Visit Page
Frontend->>API: Request Page Data (tRPC)
API->>DB: Query Content
DB->>API: Return Data
API->>Frontend: Typed Response
Frontend->>User: Rendered Page
  • JWT-based sessions with NextAuth.js
  • Role-based access control (Admin, Editor, Viewer)
  • API route protection with middleware
  • CSRF protection built into Next.js
  • Input validation with Zod schemas
  • SQL injection prevention with Prisma
  • XSS protection with Content Security Policy
  • File upload restrictions by type and size
  • HTTPS enforcement with automatic SSL
  • Environment variable protection
  • Docker container isolation
  • Regular security updates
  • Static Generation for public pages
  • Incremental Static Regeneration for updated content
  • API response caching with Redis (optional)
  • CDN caching for media assets
  • Connection pooling with Prisma
  • Database indexing on frequently queried fields
  • Query optimization with Prisma query engine
  • Regular maintenance and monitoring
  • Docker multi-stage builds for smaller images
  • Asset optimization with Next.js built-ins
  • Bundle analysis and code splitting
  • Health checks and monitoring
  1. Database: Read replicas for high-traffic sites
  2. Application: Multiple container instances
  3. Storage: CDN expansion for global reach
  4. Caching: Redis cluster for session storage
  • Application metrics with built-in Next.js analytics
  • Database monitoring with connection pool metrics
  • Error tracking with Sentry (optional)
  • Uptime monitoring with health check endpoints

This architecture provides a solid foundation that can grow with your client’s needs while maintaining developer productivity and operational simplicity.