- Features
- Quick Start
- Installation
- Usage
- Architecture
- API Endpoints
- Development
- Deployment
- Troubleshooting
- Changelog
- Contributing
- β Clean Architecture - Domain-Driven Design (DDD) approach
- β Layered Architecture - Domain, Application, Infrastructure, Interface layers
- β Dependency Inversion - Interface-based design
- β Testable - Each layer can be tested independently
- β JWT Authentication - Secure token-based authentication
- β Argon2id Password Hashing - Modern password hashing
- β Role-Based Access Control (RBAC) - Admin, Editor, Author, Viewer roles
- β Permission System - Granular permission management
- β Input Validation - Comprehensive validation system
- β Page Management - Dynamic page creation and management
- β Component System - Reusable, database-driven components
- β Media Management - File upload and media library
- β SEO Optimization - Centralized SEO management
- β Sitemap Generation - Automatic sitemap.xml generation
- β Artisan CLI - Migration and seeding management
- β Structured Logging - Go 1.21+ slog integration
- β Error Handling - Comprehensive error management
- β Hot Reload - Development mode with Air
- β Type-Safe Templates - Templ for type-safe HTML
- β SQLite Database - Lightweight, fast database
- β Component Caching - Efficient component rendering
- β Static File Serving - Optimized asset delivery
- Go 1.23 or higher
- Make (optional, for commands)
- SQLite3 (automatically included)
- Node.js 18+ (for Tailwind CSS v4, optional - only needed for CSS build)
# 1. Clone the repository
git clone https://github.com/yourusername/cacto-cms.git
cd cacto-cms
# 2. Install dependencies
make install
# 3. Setup database and seed data
./artisan migrate:fresh --seed
# 4. Run in development mode (hot reload)
make devServer: http://localhost:8080
Login with the admin user created from seed data:
- URL:
http://localhost:8080/admin/login - Email:
admin@cacto-cms.local - Password:
admin123
Available pages:
- Home:
/(Hero + About sections) - About:
/about(from seed data) - Contact:
/contact(from seed data) - Admin Login:
/admin/login - Admin Dashboard:
/admin/dashboard(after login)
make installThis command installs:
- Go module dependencies
- Templ CLI tool
- Air (for hot reload)
# Migration only (without seed)
./artisan migrate:fresh
# Migration + Seed (recommended)
./artisan migrate:fresh --seedCreate a .env file (copy from .env.example):
cp .env.example .envOr set as environment variables:
export PORT=8080
export BASE_URL=http://localhost:8080
export JWT_SECRET=your-secret-key
export ENV=development
export USE_HTTPS=false # Set to true if using HTTPSImportant: Always use a strong JWT_SECRET in production!
make help # Show all commands
make install # Install dependencies (Go + Node.js)
make dev # Run with hot reload
make run # Run normally
make build # Build (CSS + Go binaries)
make templ # Generate templ files
make css # Tailwind CSS v4 build (production, only used classes)
make css-watch # Tailwind CSS v4 watch (development, JIT)
make clean # Clean (binary, db, templ files, CSS)
make tidy # go mod tidy
make test # Run tests
make artisan # Run Artisan CLI (ARGS="migrate:fresh --seed")Tailwind CSS v4.1:
- Development:
make css-watch(ayrΔ± terminal, JIT compilation) - Production:
make build(otomatik CSS build, only used classes)
# Migration operations
./artisan migrate:fresh # Reset database and run migrations
./artisan migrate:fresh --seed # Migration + seed data
# Or with make
make artisan ARGS="migrate:fresh --seed"# Development (hot reload)
make dev
# Production
make build
./cacto-cmsCacto CMS is designed according to Clean Architecture and Domain-Driven Design principles.
βββββββββββββββββββββββββββββββββββββββ
β Interfaces Layer (HTTP, CLI) β β Communication with external world
βββββββββββββββββββββββββββββββββββββββ€
β Application Layer (Services) β β Business logic
βββββββββββββββββββββββββββββββββββββββ€
β Domain Layer (Entities) β β Core business rules
βββββββββββββββββββββββββββββββββββββββ€
β Infrastructure Layer (DB, etc) β β Technical implementations
βββββββββββββββββββββββββββββββββββββββ
cacto-cms/
βββ cmd/
β βββ server/ # HTTP server entry point
β βββ artisan/ # CLI tool (migrations, seeds)
β
βββ app/
β βββ domain/ # Domain Layer
β β βββ page/ # Page entity & repository interface
β β βββ component/ # Component entity
β β βββ user/ # User entity & roles
β β βββ media/ # Media entity
β β
β βββ application/ # Application Layer
β β βββ page/ # Page service (business logic)
β β βββ component/ # Component service
β β βββ user/ # User service
β β βββ auth/ # Authentication service
β β βββ media/ # Media service
β β
β βββ infrastructure/ # Infrastructure Layer
β β βββ database/ # DB connection, migrations & seeds
β β β βββ migrations/ # SQL migration files
β β β βββ seeds/ # Database seeders
β β βββ persistence/ # Repository implementations
β β βββ page/
β β βββ component/
β β βββ user/
β β βββ media/
β β
β βββ interfaces/ # Interface Layer
β β βββ http/
β β β βββ controller/ # HTTP controllers
β β β βββ middleware/ # Auth, logging, error handling
β β β βββ router.go # Route definitions
β β βββ templates/ # Templ templates
β β
β βββ shared/ # Shared utilities
β βββ errors/ # Error handling
β βββ logger/ # Structured logging
β βββ validation/ # Input validation
β βββ auth/ # JWT & password hashing
β βββ seo/ # SEO management
β βββ sitemap/ # Sitemap generator
β
βββ config/ # Configuration
βββ web/
β βββ static/ # Static files (CSS, JS)
β βββ uploads/ # User uploads
βββ Makefile
- Purpose: Business entities and domain logic
- Content:
- Entity definitions (Page, Component, User, Media)
- Repository interfaces (domain contract)
- Domain-specific business rules
- Dependency: Not dependent on any external layer
- Purpose: Use cases and business logic orchestration
- Content:
- Service implementations
- Business logic
- Use case coordination
- Dependency: Only depends on Domain layer
- Purpose: Technical implementations
- Content:
- Database connections
- Repository implementations
- External service integrations
- Dependency: Depends on Domain and Application layers
- Purpose: Communication with external world
- Content:
- HTTP handlers
- CLI commands (Artisan)
- Templates
- Dependency: Depends on Application layer
- Purpose: Common utilities
- Content:
- Error handling
- Logging
- Validation
- SEO utilities
- Sitemap generator
- Dependency: May depend on Domain layer
cmd/server/main.go
β
app/interfaces/http (router, controllers)
β
app/application (services)
β
app/domain (entities, interfaces)
β
app/infrastructure/persistence (implementations)
Rule: Outer layers can depend on inner layers, inner layers cannot depend on outer layers.
- Each domain entity in its own package (
app/domain/page/) - Repository interface defined in domain
- Implementation in infrastructure
- Separation of Concerns: Each layer focuses on its own responsibility
- Dependency Inversion: Domain layer is not dependent on anything
- Testability: Each layer can be tested independently
Cacto CMS has an API-first architecture. All endpoints can return both JSON and HTML:
- JSON: With
Accept: application/jsonheader orContent-Type: application/json - HTML: Returns HTML by default (for browser requests)
| Method | Endpoint | Description | Response Type |
|---|---|---|---|
| GET | / |
Home page | HTML |
| GET | /{slug} |
Dynamic page by slug | HTML |
| GET | /sitemap.xml |
Sitemap | XML |
| GET | /static/* |
Static files | Static |
| GET | /uploads/* |
Uploaded files | Static |
| Method | Endpoint | Description | Auth Required | Response Type |
|---|---|---|---|---|
| POST | /api/auth/login |
User login (API) | β | JSON |
| POST | /api/auth/register |
User registration | β | JSON |
| POST | /api/auth/logout |
User logout | β | JSON |
| GET | /admin/login |
Admin login page | β | HTML |
| POST | /admin/login |
Admin login (form/JSON) | β | HTML/JSON |
Protected routes require authentication. Admin/Editor routes require specific roles.
| Method | Endpoint | Description | Roles | Response Type |
|---|---|---|---|---|
| GET | /admin/dashboard |
Admin dashboard | admin, editor | HTML/JSON |
| POST | /admin/logout |
Admin logout | admin, editor | HTML/JSON |
Cacto CMS has an API-first architecture. All controllers can return both HTML and JSON:
- JSON Response: When request is made with
Accept: application/jsonheader - HTML Response: By default (for browser requests)
This allows:
- β Existing HTML pages continue to work
- β API endpoints return JSON from the same controller
- β A single controller serves both web and API needs
- β JSON API can be quickly used when needed
TarayΔ±cΔ±da: http://localhost:8080/admin/login
curl -X POST http://localhost:8080/admin/login \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"email": "admin@cacto-cms.local",
"password": "admin123"
}'Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"email": "admin@cacto-cms.local",
"name": "Admin User",
"role": "admin",
"is_active": true
}
}curl -X GET http://localhost:8080/admin/dashboard \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Cookie: auth_token=YOUR_JWT_TOKEN"Response:
{
"email": "admin@cacto-cms.local",
"role": "admin"
}curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "admin@cacto-cms.local",
"password": "admin123"
}'curl -X POST http://localhost:8080/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "password123",
"name": "New User"
}'app/domain/{entity}/entity.go- Entity definitionsapp/domain/{entity}/repository.go- Repository interfaceapp/application/{entity}/service.go- Business logicapp/infrastructure/persistence/{entity}/repository.go- Implementationapp/interfaces/http/controller/{entity}_controller.go- HTTP controller
- Update component entity:
app/domain/component/entity.go - Add to component renderer:
app/shared/component/renderer.go - Create template:
app/interfaces/templates/components/new_component.templ - Run
make templ
- Create
app/infrastructure/database/migrations/003_new_migration.sql - File name must be sequential (001_, 002_, etc.)
- Write SQL file
- Migration runs automatically
- Create
app/infrastructure/database/seeds/03_new_data.go - Write seed function
- Add to
app/infrastructure/database/seeds/seeder.go - Run
./artisan migrate:fresh --seed
- Edit
.templfile - Run
make templortempl generate *_templ.gofile is automatically generated
- Edit
web/static/css/input.cssfile - Development: Auto-updates if
make css-watchis running (JIT) - Production:
make buildautomatically builds CSS (only used classes) - See TAILWIND.md for detailed information
# Open SQLite shell
sqlite3 cacto.db
# List tables
.tables
# View page data
SELECT * FROM pages;
# Add new page
INSERT INTO pages (slug, title, content, status)
VALUES ('test', 'Test Page', 'Test content', 'published');
# Exit
.quit# Run all tests
make test
# Test a specific package
go test ./app/application/page/...# Build
make build
# Environment variables ayarla
export ENV=production
export JWT_SECRET=your-production-secret
export BASE_URL=https://yourdomain.com
# ΓalΔ±ΕtΔ±r
./cacto-cms# Connect to server via SSH
ssh root@your-server-ip
# Update system
apt update && apt upgrade -y
# Install Go
wget https://go.dev/dl/go1.23.0.linux-amd64.tar.gz
rm -rf /usr/local/go
tar -C /usr/local -xzf go1.23.0.linux-amd64.tar.gz
# Add to PATH
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
# Install required tools
apt install -y git nginx sqlite3# Clone project
git clone https://github.com/youruser/cacto-cms.git /home/cacto/apps/cacto-cms
cd /home/cacto/apps/cacto-cms
# Install dependencies
make install
# Build
make build
# Environment variables
cat > .env << 'EOF'
PORT=8080
BASE_URL=https://yourdomain.com
DB_PATH=/home/cacto/apps/cacto-cms/cacto.db
UPLOAD_DIR=/home/cacto/apps/cacto-cms/web/uploads
ENV=production
JWT_SECRET=your-production-secret
EOF
# Set directory permissions
chmod +x cacto-cms
mkdir -p web/uploads logs
chmod 755 web/uploadssudo nano /etc/systemd/system/cacto-cms.service[Unit]
Description=Cacto CMS
After=network.target
[Service]
Type=simple
User=cacto
WorkingDirectory=/home/cacto/apps/cacto-cms
ExecStart=/home/cacto/apps/cacto-cms/cacto-cms
Restart=on-failure
RestartSec=5s
Environment="PATH=/usr/local/go/bin:/usr/bin:/bin"
# Logs
StandardOutput=append:/home/cacto/apps/cacto-cms/logs/app.log
StandardError=append:/home/cacto/apps/cacto-cms/logs/error.log
[Install]
WantedBy=multi-user.target# Activate service
systemctl daemon-reload
systemctl enable cacto-cms
systemctl start cacto-cms
# Check status
systemctl status cacto-cms
# Watch logs
journalctl -u cacto-cms -f# HTTP -> HTTPS Redirect
server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$server_name$request_uri;
}
}
# HTTPS Server
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL SertifikalarΔ± (Let's Encrypt ile alΔ±nacak)
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# SSL AyarlarΔ±
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Gzip Compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript
application/x-javascript application/xml+rss
application/javascript application/json;
# Static files
location /static/ {
alias /home/cacto/apps/cacto-cms/web/static/;
expires 1y;
add_header Cache-Control "public, immutable";
}
location /uploads/ {
alias /home/cacto/apps/cacto-cms/web/uploads/;
expires 30d;
add_header Cache-Control "public";
}
# Sitemap
location = /sitemap.xml {
alias /home/cacto/apps/cacto-cms/web/static/sitemap.xml;
expires 1d;
}
# Go App (reverse proxy)
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
access_log /var/log/nginx/cacto-cms-access.log;
error_log /var/log/nginx/cacto-cms-error.log;
}go install github.com/a-h/templ/cmd/templ@latest
export PATH=$PATH:$(go env GOPATH)/bin
# or Makefile already handles it: make installβ FIXED:
- Migrations:
app/infrastructure/database/migrations/ - Seeds:
app/infrastructure/database/seeds/(same location as migrations)
make tidy# Create .env file
cp .env.example .env
# Change PORT=8081 etc.# Reset database
make clean
./artisan migrate:fresh --seed# Update dependencies
make tidy
make install
make buildCacto CMS implements enterprise-level security measures:
- JWT (JSON Web Token) based authentication
- Argon2id Password Hashing - Modern, secure password hashing
- Role-Based Access Control (RBAC) - Admin, Editor, Author, Viewer roles
- Cookie-based - Automatic cookie management for browsers
- Header-based -
Authorization: Bearer TOKENfor API requests - Secure Cookies -
Secureflag automatically enabled when HTTPS is detected
- HTML Sanitization - All user-generated content is sanitized using bluemonday
- Input Validation - Comprehensive struct-based validation
- SQL Injection Protection - Prepared statements throughout
- Path Traversal Prevention - All file paths are validated
- X-Content-Type-Options: nosniff - Prevents MIME type sniffing
- X-Frame-Options: DENY - Prevents clickjacking
- X-XSS-Protection: 1; mode=block - XSS protection
- Content-Security-Policy - Restricts resource loading
- Strict-Transport-Security - HSTS for HTTPS connections
- Referrer-Policy - Controls referrer information
- Development: Allows all origins (
*) - Production: Only allows configured origins (from
BASE_URLorALLOWED_ORIGINS) - Configurable: Set
ALLOWED_ORIGINSenvironment variable for custom origins
- Auth Endpoints: 5 requests per minute (login, register)
- API Endpoints: 60 requests per minute
- IP-based: Rate limiting by client IP address
- Production Mode: Generic error messages (no internal details exposed)
- Development Mode: Detailed error messages for debugging
- Structured Errors: Consistent error response format
- MIME Type Validation - Validates file types
- File Size Limits - Configurable max file size (default: 10MB)
- Filename Sanitization - Prevents path traversal and malicious filenames
- Content Validation - Magic number detection for file types
- Path Validation - Prevents directory traversal attacks
- CSRF Middleware - Available for state-changing requests
- Double Submit Cookie - Token-based CSRF protection
- Configurable - Can be enabled per route group
Default users created from seed data:
- Admin:
admin@cacto-cms.local/admin123 - Editor:
editor@cacto-cms.local/admin123
Before deploying to production, ensure:
- β
JWT Secret: Set a strong, random
JWT_SECRET(minimum 32 characters) - β
HTTPS: Set
USE_HTTPS=trueor usehttps://inBASE_URL - β
Environment: Set
ENV=production - β
CORS: Configure
ALLOWED_ORIGINSif needed (defaults toBASE_URL) - β Passwords: Change default admin/editor passwords
- β Database: Use secure database path (not world-readable)
- β Upload Directory: Set proper permissions on upload directory
- β Error Logging: Monitor error logs for security issues
- β Rate Limiting: Verify rate limiting is working
- β Security Headers: Verify all security headers are present
Required for Production:
ENV=production
JWT_SECRET=<strong-random-secret-min-32-chars>
BASE_URL=https://yourdomain.com
USE_HTTPS=true # Or set BASE_URL to https://Optional:
ALLOWED_ORIGINS=https://yourdomain.com,https://www.yourdomain.com
PORT=8080
DB_PATH=/secure/path/to/cacto.db
UPLOAD_DIR=/secure/path/to/uploads- JWT Secret: Generate using:
openssl rand -base64 32 - HTTPS: Always use HTTPS in production (required for secure cookies)
- Password Policy: Implement strong password requirements
- Regular Updates: Keep dependencies updated
- Monitoring: Set up error logging and monitoring
- Backup: Regular database backups
- Access Control: Limit server access to authorized personnel only
- Firewall: Configure firewall rules appropriately
- SSL/TLS: Use strong SSL/TLS configuration
- Security Headers: Verify all security headers are present (use securityheaders.com)
Public Directories:
- β
web/static/- Public static files (CSS, JS, images) - β
web/uploads/- Public uploaded files
Protected:
- β Application code - Not accessible via web
- β Database files - Not in web directory
- β Configuration files - Not in web directory
- β Source code - Not accessible
Path Traversal Protection:
- β All file paths are validated
- β
..sequences are blocked - β Absolute paths are rejected
- β Null bytes are filtered
- β Clean Architecture implementation with Domain-Driven Design
- β Page management system with dynamic routing
- β Component-based architecture with database-driven components
- β JWT Authentication system with Argon2id password hashing
- β Role-Based Access Control (RBAC) with Admin, Editor, Author, Viewer roles
- β Media management system with file validation
- β SEO management with centralized meta tag handling
- β Automatic sitemap generation
- β Artisan CLI for migrations and seeding
- β Structured error handling system
- β Structured logging with Go 1.21+ slog
- β Input validation system
- β Environment-based configuration
- β Component renderer with registry pattern
- β Seed management system
- β Protected routes with authentication middleware
- β Error handling middleware
- β CORS middleware
- β Request logging middleware
- Domain layer with entities and repository interfaces
- Application layer with business logic services
- Infrastructure layer with database and persistence implementations
- Interface layer with HTTP controllers and templates
- Shared utilities for common functionality
- JWT token-based authentication
- Argon2id password hashing
- Role-based permission system
- Input validation
- CORS configuration
- Hot reload with Air
- Type-safe templates with Templ
- Makefile with common commands
- Artisan CLI for database operations
- Comprehensive documentation
- Admin dashboard UI
- Media upload handler
- File upload endpoint
- Content versioning
- Full-text search
- Caching layer
- API documentation (Swagger/OpenAPI)
- Unit and integration tests
- Docker support
- Rate limiting
- Email notifications
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Use Go fmt
- Write tests
- Follow Clean Architecture principles
- Add documentation
This project is licensed under the MIT License. See the LICENSE file for details.
- Templ - Type-safe HTML templates
- Chi - Lightweight HTTP router
- HTMX - Modern web interactions
- Go Community - Amazing Go ecosystem
Cacto CMS - Performance-focused, modern, enterprise-ready CMS
Made with β€οΈ using Go