@otherdev-software/canvas
v1.0.0
Published
OtherDev Canvas - A powerful multi-tenant headless CMS with role-based access control, custom branding, and subdomain routing for agencies and SaaS platforms
Maintainers
Readme
OtherDev Canvas
A powerful multi-tenant headless CMS with enterprise-grade features for agencies and SaaS platforms.
Features
- Multi-Tenancy - Built-in tenant isolation with subdomain routing
- Role-Based Access Control - Super-admin, Tenant-admin, and User roles
- Whitelabel Ready - Custom branding, logos, and admin panel customization
- Rich Content Management - Blog posts, categories, media library with folders
- PostgreSQL by Default - Production-ready database adapter
- Next.js 15 App Router - Modern React 19 with server components
- Lexical Rich Text Editor - Advanced content editing with custom features
- Type-Safe - Full TypeScript support with auto-generated types
- Shadcn/UI Components - Beautiful, accessible UI components
- Multi-Database Support - PostgreSQL and MongoDB adapters included
Installation
Quick Start
# Install the package
npm install @otherdev/canvas
# Or download and extract
npx degit otherdev/canvas my-project
cd my-projectManual Installation
# Clone or install
pnpm add @otherdev/canvas
# Setup environment
cp .env.example .env
# Install dependencies
pnpm install
# Generate TypeScript types
pnpm generate:types
# Start development server
pnpm devVisit http://localhost:3000/admin to access the admin panel.
Environment Variables
Create a .env file in your project root:
# Database - PostgreSQL (recommended)
DATABASE_URI=postgresql://user:password@localhost:5432/canvas_db
# Application Secret (min 32 characters)
PAYLOAD_SECRET=your-super-secret-32-char-minimum-key-here
# App Configuration
NEXT_PUBLIC_APP_URL=http://localhost:3000
MASTER_DOMAIN=localhost:3000Database Setup
PostgreSQL (Recommended):
# Create database
createdb canvas_db
# Or use a managed service (Supabase, Neon, Railway)
DATABASE_URI=postgresql://user:pass@host:5432/dbMongoDB (Alternative):
# Update payload.config.ts to use mongodbAdapter
DATABASE_URI=mongodb://127.0.0.1:27017/canvas_dbMulti-Tenant Architecture
How It Works
OtherDev Canvas provides complete tenant isolation:
- Tenants Collection - Each customer/organization is a tenant
- Subdomain Routing -
tenant-name.yoursite.comautomatically routes to tenant - Scoped Content - Blog posts, media, and categories are tenant-specific
- User Assignments - Users can belong to multiple tenants with different roles
Subdomain Setup (Development)
For local development with subdomains, add to your /etc/hosts (Mac/Linux) or C:\Windows\System32\drivers\etc\hosts (Windows):
127.0.0.1 tenant-a.localhost
127.0.0.1 tenant-b.localhost
127.0.0.1 client1.localhostAccess admin panel at: http://localhost:3000/admin
Access tenant frontend: http://tenant-a.localhost:3000
Production Subdomain Setup
Update next.config.mjs:
has: [{
type: 'host',
value: '(?<tenant>[^.]+)\\.yourdomain\\.com'
}]User Roles
Super Admin
- Full access to all tenants and settings
- Can create/edit/delete any content
- Manage all users and tenants
Tenant Admin
- Access only to assigned tenant(s)
- Manage content within their tenant
- Can manage users within their tenant
User
- Basic read/write access within assigned tenant
- Limited administrative capabilities
Collections
Tenants (tenants)
Manage customer organizations with custom settings.
Users (users)
Authentication-enabled with role-based permissions.
Blog Posts (blog-posts)
Rich content with Lexical editor, tenant-scoped.
Categories (categories)
Organize content, tenant-scoped.
Media (media)
File uploads with image resizing, folders enabled, tenant-scoped.
Customization
Branding
Update src/graphics/ with your logo:
Logo/logo.svg- Login page logoIcon/icon.svg- Admin panel icon
Update src/payload.config.ts:
admin: {
meta: {
titleSuffix: ' - Your Company Name',
description: 'Your custom description',
}
}Custom Collections
Add new collections in src/collections/:
// src/collections/Products.ts
import { CollectionConfig } from 'payload'
export const Products: CollectionConfig = {
slug: 'products',
fields: [
{ name: 'name', type: 'text', required: true },
{ name: 'price', type: 'number', required: true },
],
}Register in src/payload.config.ts:
import { Products } from './collections/Products'
export default buildConfig({
collections: [Users, Tenants, BlogPosts, Categories, Media, Products],
})Development
# Start dev server
pnpm dev
# Generate TypeScript types
pnpm generate:types
# Generate import map (after adding admin components)
pnpm generate:importmap
# Run linter
pnpm lint
# Format code
pnpm format
# Run tests
pnpm testProduction
Build
pnpm buildStart
pnpm startDeployment
Vercel (Recommended):
- Connect your GitHub repo
- Add environment variables
- Deploy
Self-Hosted:
- Ensure PostgreSQL is accessible
- Set
DATABASE_URIandPAYLOAD_SECRET - Run
pnpm build && pnpm start
Docker:
docker-compose up -dAPI Access
REST API
# Get all blog posts for a tenant
GET /api/blog-posts?where[tenant][equals]=<tenant-id>
# Create a blog post
POST /api/blog-postsGraphQL
# GraphQL Playground
http://localhost:3000/api/graphql-playground
# GraphQL Endpoint
http://localhost:3000/api/graphqlProject Structure
otherdev-canvas/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── (payload)/ # Payload admin & API routes
│ │ └── (frontend)/ # Your frontend routes
│ ├── collections/ # Payload collections
│ ├── components/ # React components
│ │ ├── ui/ # Shadcn components
│ │ └── admin/ # Admin customizations
│ ├── graphics/ # Logos and branding
│ └── payload.config.ts # Payload configuration
├── public/ # Static assets
└── package.jsonTroubleshooting
Database Connection Issues
# Test PostgreSQL connection
psql $DATABASE_URI
# Check if database exists
psql -lAdmin Panel Not Loading
# Regenerate import map
pnpm generate:importmap
# Clear Next.js cache
rm -rf .next
pnpm devType Errors
# Regenerate types
pnpm generate:typesDocumentation
Support
- GitHub Issues: https://github.com/otherdev/canvas/issues
- Documentation: https://github.com/otherdev/canvas/wiki
License
MIT License - see LICENSE file for details.
