SveltyCMS Complete Workflow Guide
Comprehensive guide covering installation, initialization, testing, and CI/CD workflows for SveltyCMS
Last updated: 10/25/2025
SveltyCMS Complete Workflow Guide
This comprehensive guide covers the entire SveltyCMS lifecycle: installation, first-time setup, server restart workflows, testing strategies, and automated CI/CD deployment. The system is designed to be intelligent, avoiding unnecessary recompilation while maintaining UUID consistency for collections.
๐ This unified guide replaces:
installation.mdx,testing.mdx, andTESTING_GUIDE.md.old
Table of Contents
Part I: Installation & Setup
- Prerequisites
- Quick Installation
- Manual Installation
- First-Time Setup Flow
- Post-Installation Configuration
Part II: System Architecture
- Visual Overview
- Server Restart Flow
- Collection UUID Management
See Compilation Pipeline for detailed architecture.
- Key Components
- State Machine
- Compilation Pipeline
Part III: Testing & CI/CD
- Testing Overview
- Unit Testing with Bun
- E2E Testing with Playwright
- GitHub Actions CI/CD
- Automated Setup Scripts
Part IV: Troubleshooting & Reference
Part I: Installation & Setup
Prerequisites
Before installing SveltyCMS, ensure you have the following installed:
Required Software
1. Node.js (>=24)
- Download: https://nodejs.org/
- Check version:
node --version - Why: Runtime environment for JavaScript
2. Package Manager
Choose one of the following:
- Bun (recommended - 3-4x faster runtime)
curl -fsSL https://bun.sh/install | bash - npm (comes with Node.js)
npm --version - Yarn
npm install -g yarn - pnpm
npm install -g pnpm
3. Git
- Download: https://git-scm.com/
- Check version:
git --version - Why: Version control and repository cloning
4. Database
MongoDB (recommended for first install)
- MongoDB Atlas (cloud): https://www.mongodb.com/cloud/atlas
- Local MongoDB: https://www.mongodb.com/try/download/community
- Connection string format:
- Local:
mongodb://localhost:27017/sveltycms - Atlas:
mongodb+srv://username:password@cluster.mongodb.net/dbname
- Local:
MariaDB/MySQL (alternative)
- Download: https://mariadb.org/download/
- Connection format:
host:port(e.g.,localhost:3306)
Quick Installation
The fastest way to get started with SveltyCMS.
Step 1: Clone Repository
git clone https://github.com/SveltyCMS/SveltyCMS.git
cd SveltyCMS
Step 2: Install Dependencies
Choose your package manager:
Bun (fastest)
bun install
bun run dev
npm
npm install
npm run dev
Yarn
yarn install
yarn dev
pnpm
pnpm install
pnpm dev
Step 3: Setup Wizard
The setup wizard launches automatically on first run at http://localhost:5173/setup:
-
Database Configuration
- Choose: MongoDB, MariaDB, or PostgreSQL
- Enter connection details
- Test connection automatically
-
Database Driver Installation
- Automatically installs required drivers
- Detects your package manager
- Handles dependencies
-
System Language Selection
- Choose default language
- Configures internationalization
-
Initial Data Seeding
- Seeds system settings (53 keys)
- Creates default theme
- Sets up base configuration
-
Admin User Creation
- Set admin email
- Create secure password
- Generate session secrets
-
Completion
- Builds and starts development server
- Opens CMS dashboard automatically
- No server restart required! โจ
Manual Installation
For advanced users who need more control over the installation process.
Step 1: Clone and Install
git clone https://github.com/SveltyCMS/SveltyCMS.git
cd SveltyCMS
bun install # or npm/yarn/pnpm
Step 2: Install Database Driver
Install the driver for your chosen database:
# MongoDB
bun add mongoose
# MariaDB/MySQL
bun add mariadb
# PostgreSQL (when available)
bun add pg
Step 3: Create Environment File
Create config/private.ts in the project root:
import { createPrivateConfig } from '../src/utils/config';
export const privateEnv = createPrivateConfig({
// Database Configuration
DB_TYPE: 'mongodb',
DB_HOST: 'localhost',
DB_PORT: 27017,
DB_NAME: 'sveltycms',
DB_USER: 'admin',
DB_PASSWORD: 'your_secure_password',
// Security (generate with: openssl rand -hex 32)
JWT_SECRET_KEY: 'your_generated_secret_here',
ENCRYPTION_KEY: 'your_encryption_key_here',
// Multi-Tenancy (optional)
MULTI_TENANT: false
});
Generate Secure Secrets:
# Using Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
# Using OpenSSL
openssl rand -base64 32
Step 4: Test Database Connection
Start the development server and test the connection:
bun run dev
Visit http://localhost:5173/setup or use the API directly:
curl -X POST http://localhost:5173/setup?/testDatabase \
-H "Content-Type: application/json" \
-d '{
"type": "mongodb",
"host": "localhost",
"port": 27017,
"name": "sveltycms",
"user": "admin",
"password": "your_password"
}'
Step 5: Seed Initial Data
Run the seed script or use the API:
# Using seed script (recommended for CI/CD)
bun run scripts/seed-cms.js
# Or through the setup wizard at /setup
Step 6: Create Admin User
# Using create-admin script (recommended for CI/CD)
bun run scripts/create-admin.js
# Or through the setup wizard at /setup
Post-Installation Configuration
After completing installation, configure your SveltyCMS instance:
1. Login to Admin Panel
Visit http://localhost:5173/admin (or your custom URL) and login with your admin credentials.
2. Configure System Settings
Navigate to Settings and configure:
- Site Information: Name, description, URL
- Default Language: Choose primary language
- Theme Preferences: Light/dark mode, accent colors
- Email Settings: SMTP configuration for notifications
- Cache Settings: Enable/disable caching, Redis configuration
3. Create Collections
Navigate to Collections to:
- Create content collections (Posts, Pages, etc.)
- Define field schemas
- Set up relationships between collections
- Configure permissions
4. Set Up Users
Navigate to Users to:
- Create additional user accounts
- Assign roles (admin, editor, viewer)
- Configure permissions
- Manage user sessions
5. Install Widgets
Navigate to Widgets to:
- Browse available widgets
- Install additional functionality
- Activate required widgets
- Configure widget settings
Development & Production
Development Server
Start the development server with hot module reload:
# Using Bun (recommended)
bun run dev
# Using npm
npm run dev
# Using Yarn
yarn dev
# Using pnpm
pnpm dev
The server will start at:
- Frontend:
http://localhost:5173 - Admin Panel:
http://localhost:5173/admin - API:
http://localhost:5173/api - GraphQL:
http://localhost:5173/api/graphql
Production Build
Build for production:
# Build
bun run build
# Preview production build
bun run preview
Deployment Options
Vercel
npm install -g vercel
vercel --prod
Netlify
npm install -g netlify-cli
netlify deploy --prod
Docker
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["node", "build"]
docker build -t sveltycms .
docker run -p 3000:3000 --env-file .env sveltycms
Traditional Server (PM2)
npm install -g pm2
npm run build
pm2 start build/index.js --name sveltycms
pm2 save
pm2 startup
Production Environment Variables
Ensure these are set in production:
NODE_ENV=production
SITE_URL=https://your-domain.com
PUBLIC_URL=https://your-domain.com
# Use strong secrets!
JWT_SECRET_KEY=<generate-with-openssl-rand-base64-32>
ENCRYPTION_KEY=<generate-with-openssl-rand-base64-32>
Directory Structure
After installation, your project structure:
SveltyCMS/
โโโ build/ # Production build output
โโโ config/ # Configuration files
โ โโโ private.ts # Database credentials (auto-generated)
โ โโโ roles.ts # Role definitions
โ โโโ collections/ # Collection schemas (user-created)
โโโ compiledCollections/ # Compiled collections (auto-generated)
โ โโโ Collections/
โ โโโ Menu/
โโโ docs/ # Documentation
โโโ scripts/ # Automation scripts
โ โโโ seed-cms.js # Database seeding script
โ โโโ create-admin.js # Admin user creation script
โโโ src/
โ โโโ routes/ # SvelteKit routes
โ โ โโโ admin/ # Admin panel
โ โ โโโ api/ # API endpoints
โ โ โโโ setup/ # Setup wizard
โ โโโ databases/ # Database adapters
โ โโโ widgets/ # Widget system
โ โโโ components/ # Svelte components
โ โโโ stores/ # Svelte stores
โ โโโ utils/ # Utility functions
โโโ static/ # Static assets
โโโ tests/ # Test files
โ โโโ bun/ # Unit tests
โ โโโ playwright/ # E2E tests
โโโ .github/
โ โโโ workflows/ # GitHub Actions
โ โโโ playwright.yml # Test workflow
โ โโโ auto-release.yaml # Release workflow
โโโ package.json
โโโ svelte.config.js
โโโ tailwind.config.ts
โโโ playwright.config.ts
โโโ bunfig.toml
โโโ tsconfig.json
Part II: System Architecture
Visual Overview
Complete System Lifecycle
First-Time Setup Architecture
Server Restart Architecture
First-Time Setup Flow
Phase 1: Vite Startup (Build Time)
File: vite.config.ts
Created config/private.ts:
export const privateEnv = createPrivateConfig({
DB_TYPE: 'mongodb',
DB_HOST: '', // โ Empty values
DB_PORT: 27017,
DB_NAME: '', // โ Empty values
DB_USER: '',
DB_PASSWORD: '',
JWT_SECRET_KEY: '', // โ Empty
ENCRYPTION_KEY: '', // โ Empty
MULTI_TENANT: false
});
Phase 2: Server Hooks (Runtime)
File: src/hooks.server.ts
๐ For detailed middleware architecture, see Server Hooks & Middleware
Phase 3: Setup GUI Interaction
File: src/routes/setup/+page.svelte
User completes setup wizard:
Step 1: Database Configuration
โ
Step 2: Database Test โ /setup?/testDatabase
โ
Step 3: System Language Selection
โ
Step 4: Seed Data โ /setup?/seedDatabase
โ
Step 5: Admin User Creation โ /setup?/completeSetup
Phase 4: Database Test (Server Function)
Action: src/routes/setup/+page.server.ts (Action: testDatabase)
POST /setup?/testDatabase
Body: {
type: "mongodb",
host: "localhost",
port: 27017,
name: "sveltycms",
user: "admin",
password: "secret123"
}
Process:
- Detects package manager (bun/npm/pnpm/yarn)
- Installs MongoDB driver if missing (
mongoose) - Builds connection string
- Tests connection with 15s timeout
- Returns detailed validation results
Response:
{
"success": true,
"message": "Connection successful",
"details": {
"authenticated": true,
"dbStats": { "collections": 0, "dataSize": 0 },
"warnings": []
}
}
Phase 5: Seed Database
Endpoint: /setup?/seedDatabase/+server.ts
Called when user clicks โNextโ after successful DB test. This process now runs in the background to prevent UI timeouts and allow real-time progress tracking.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Write config/private.ts โ
โ - Writes DB credentials from test step โ
โ - Generates JWT_SECRET_KEY (32 bytes base64) โ
โ - Generates ENCRYPTION_KEY (32 bytes base64) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Initialize database adapter (setup mode) โ
โ - getSetupDatabaseAdapter(dbConfig) โ
โ - Creates MongoDBAdapter โ
โ - Connects to database โ
โ - Calls setupAuthModels() โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Seed default data (seed.ts) โ
โ A. seedSettings(adapter) โ
โ - Creates system_settings collection โ
โ - Seeds defaultPublicSettings (53 keys) โ
โ - Seeds defaultPrivateSettings (23 keys) โ
โ B. seedDefaultTheme(adapter) โ
โ - Creates system_themes collection โ
โ - Seeds SveltyCMSTheme โ
โ C. seedCollectionsForSetup(adapter) โ
โ - Scans compiledCollections folder โ
โ - Creates collection models in MongoDB โ
โ - Reports progress via setupManager โ
โ - Returns firstCollection info โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Key Function: seedCollectionsForSetup()
// File: src/routes/setup?/seedDatabase.ts
export async function seedCollectionsForSetup(dbAdapter) {
// 1. Scan filesystem for compiled collections
const { scanCompiledCollections } = await import('@src/content/collectionScanner');
const collections = await scanCompiledCollections();
// 2. Register each collection as a model
for (const schema of collections) {
await dbAdapter.collection.createModel(schema);
// โ ๏ธ Creates MongoDB collection: collection_<uuid>
}
// 3. Return first collection for fast redirect
return { firstCollection: { name: 'Posts', path: '/Collections/Posts' } };
}
Database Collections Created:
system_settings โ Public/private settings
system_themes โ Theme configurations
system_content_structure โ Navigation/hierarchy (empty for now)
collection_<uuid_1> โ First collection (e.g., Posts)
collection_<uuid_2> โ Second collection (e.g., Names)
Phase 6: Complete Setup
Endpoint: /setup?/completeSetup/+server.ts
Called when user submits admin user form.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Parse private.ts from filesystem โ
โ - Bypasses Vite's import cache โ
โ - Uses regex to extract config values โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Create setup database adapter โ
โ - getSetupDatabaseAdapter(dbConfig) โ
โ - Creates Auth instance โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Create admin user + session (single transaction)โ
โ - setupAuth.createUserAndSession({ โ
โ username, email, password, โ
โ role: 'admin', isRegistered: true โ
โ }) โ
โ - Inserts into auth_users collection โ
โ - Creates session in auth_sessions collection โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Initialize global system (db.ts) โ
โ - initializeWithFreshConfig() โ
โ - Reloads private.ts from filesystem โ
โ - Connects global dbAdapter โ
โ - Loads settings from database โ
โ - Initializes ThemeManager โ
โ - Initializes MediaFolder โ
โ - State: IDLE โ INITIALIZING โ READY โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. Initialize ContentManager โ
โ - contentManager.initialize(undefined, true) โ
โ - Loads collections from database โ
โ - Builds content structure cache โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 6. Invalidate caches โ
โ - invalidateSettingsCache() โ
โ - invalidateSetupCache() โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 7. Send welcome email (optional, non-fatal) โ
โ - POST /api/sendMail โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 8. Set session cookie โ
โ - Creates httpOnly session cookie โ
โ - Sets theme cookies โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 9. Return redirect path โ
โ - Uses firstCollection from seed step (fast!) โ
โ - Redirects to /{lang}/{firstCollection.path} โ
โ - NO SERVER RESTART REQUIRED! โจ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Response:
{
"success": true,
"message": "Setup complete! Welcome to SveltyCMS! ๐",
"redirectPath": "/en/Collections/Posts",
"loggedIn": true,
"requiresHardReload": false,
"requiresServerRestart": false
}
Server Restart Flow
Phase 1: Vite Startup (Build Time)
File: vite.config.ts
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Vite starts โ
โ - Checks if config/private.ts exists โ
โ - isSetupComplete() โ true (config exists + โ
โ has valid DB credentials) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. cmsWatcherPlugin() activates โ
โ - Initializes collection structure โ
โ - Compiles collections intelligently โ
โ - Sets up file watchers โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Phase 2: Intelligent Collection Compilation
File: src/utils/compilation/compile.ts
The compilation system uses content hashing and UUID preservation to avoid unnecessary recompilation:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Scan existing compiled collections โ
โ - Builds map: path โ { jsPath, uuid, hash } โ
โ - Extracts UUID and hash from JS files โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Scan source collections (config/collections) โ
โ - Gets list of .ts files โ
โ - Calculates content hash for each โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Smart recompilation decision โ
โ For each collection: โ
โ IF hash matches existing compiled file โ
โ โ SKIP (no changes detected) โ
โ โ PRESERVE existing UUID โ
โ ELSE โ
โ โ RECOMPILE โ
โ โ PRESERVE existing UUID (if found) โ
โ โ GENERATE new UUID (if new file) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. AST transformation โ
โ - Converts TypeScript to JavaScript โ
โ - Adds .js extensions to imports โ
โ - Injects _id (UUID) into schema โ
โ - Injects __HASH__ comment โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. Cleanup orphaned files โ
โ - Removes .js files without .ts source โ
โ - Removes empty directories โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Example Compiled Collection:
// compiledCollections/Collections/Posts.js
// __HASH__:a7f3e9c2d8b1f4a6e3c9d2b8f1a4e6c3
export const schema = {
_id: '550e8400-e29b-41d4-a716-446655440000', // โ UUID preserved!
name: 'Posts',
icon: 'bi:file-text',
fields: [
{ label: 'Title', db_fieldName: 'title', widget: 'text' },
{ label: 'Content', db_fieldName: 'content', widget: 'richtext' }
]
};
Phase 3: Server Initialization
File: src/hooks.server.ts + src/databases/db.ts
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ handleSystemState โ
โ - System state: IDLE โ
โ - First request triggers: await dbInitPromise โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ initializeOnRequest() (db.ts) โ
โ 1. Load private config (privateEnv) โ
โ 2. Connect to database โ
โ 3. Load adapters (MongoDBAdapter) โ
โ 4. Setup auth models โ
โ 5. Load settings from database โ
โ 6. Initialize default theme โ
โ 7. Initialize theme manager โ
โ 8. Initialize media folder โ
โ 9. Initialize virtual folders โ
โ State: IDLE โ INITIALIZING โ READY โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ContentManager auto-initializes on first access โ
โ - Scans compiledCollections โ
โ - Registers collection models in database โ
โ - Builds content structure cache โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Collection UUID Management
UUID Assignment Strategy
The Problem: Collections need stable, persistent IDs for:
- Database table names (
collection_<uuid>) - Content references (foreign keys)
- API routes
- Permissions/roles
The Solution: UUIDs are assigned once at compilation and preserved across restarts.
UUID Lifecycle
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. New Collection Created โ
โ config/collections/Posts.ts โ
โ export const schema = { name: "Posts", ... } โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. First Compilation โ
โ - Generates new UUID โ
โ - Injects into schema._id โ
โ - Saves to compiledCollections/Collections/ โ
โ Posts.js โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Collection Modified โ
โ config/collections/Posts.ts changed โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Smart Recompilation โ
โ - Detects hash change โ
โ - PRESERVES existing UUID from compiled file โ
โ - Recompiles with same UUID โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. Server Restart โ
โ - Reads compiled collections โ
โ - UUIDs remain stable โ
โ - Database tables remain consistent โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
UUID Extraction Logic
File: src/utils/compilation/compile.ts
// Extract UUID from compiled JS file
function extractUUIDFromJs(content: string): string | null {
const match = content.match(/_id:\s*["']([^"']+)["']/);
return match ? match[1] : null;
}
// Extract hash from compiled JS file
function extractHashFromJs(content: string): string | null {
const match = content.match(/__HASH__:(\w+)/);
return match ? match[1] : null;
}
AST Transformation:
// Injects UUID into schema during compilation
const schemaUuidTransformer =
(uuid: string): ts.TransformerFactory<ts.SourceFile> =>
(context) =>
(sourceFile) => {
// Finds: export const schema = { ... }
// Injects: _id: "uuid-here"
// Result: export const schema = { _id: "uuid-here", ... }
};
Key Components
1. Configuration Files
| File | Purpose | Created When |
|---|---|---|
config/private.ts |
Database credentials, security keys | Vite startup (empty) โ Seed step (populated) |
config/collections/*.ts |
Collection definitions (TypeScript) | User-created |
compiledCollections/**/*.js |
Compiled collections (JavaScript + UUID) | Build time |
2. API Endpoints
| Endpoint | Purpose | Called When |
|---|---|---|
/setup?/testDatabase |
Validates DB connection | Setup wizard (Step 2) |
/setup?/seedDatabase |
Seeds settings, themes, collections | Setup wizard (Step 4) |
/setup?/completeSetup |
Creates admin user, initializes system | Setup wizard (Step 5) |
3. Hooks & Middleware
| Hook | Purpose | Order |
|---|---|---|
handleSystemState |
Blocks requests if system FAILED | 1st |
handleSetup |
Redirects to /setup if incomplete | 2nd |
handleAuthentication |
Validates session, identifies user | 6th |
4. Core Services
| Service | Purpose | File |
|---|---|---|
dbAdapter |
Database abstraction layer | src/databases/db.ts |
ContentManager |
Collection management | src/content/content-manager.ts |
Auth |
Authentication/authorization | src/databases/auth/index.ts |
SettingsService |
Settings cache management | src/services/settingsService.ts |
State Machine
System States
IDLE โ INITIALIZING โ READY โ DEGRADED โ FAILED
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโ
(reinit)
| State | Description | Allowed Routes |
|---|---|---|
| IDLE | No valid config or not initialized | /setup, /api/system/health, /login, /static, /.well-known |
| INITIALIZING | Loading config, connecting to DB | /api/system/health |
| READY | Fully operational | All routes |
| DEGRADED | Some services failed, but operational | All routes (with warnings) |
| FAILED | Critical failure, unusable | None (503 errors) |
Transition Triggers
// File: src/stores/system.ts
export function transitionTo(newState: SystemState, reason?: string) {
const oldState = state.overallState;
state.overallState = newState;
state.performanceMetrics.stateTransitions.push({
from: oldState,
to: newState,
timestamp: Date.now(),
reason
});
}
Known Issues
Issue #1: Collection UUID Tables
Problem:
During seedCollectionsForSetup(), only one collection_<uuid> table gets created in MongoDB instead of one per collection.
Expected Behavior:
collection_550e8400-e29b-41d4-a716-446655440000 (Posts)
collection_7c9e6679-7425-40de-944b-e07fc1f90ae7 (Names)
collection_a8098c1a-f86e-11da-bd1a-00112444be1e (WidgetTest)
Actual Behavior:
collection_550e8400-e29b-41d4-a716-446655440000 (Only one table)
Root Cause (Suspected):
- Race Condition: Multiple
createModel()calls execute in parallel without proper locking - Mongoose Model Registry: Mongoose may be caching models by name, causing conflicts
- MongoDB Collection Creation: MongoDB creates collections lazily on first insert, but the model registration may be conflicting
Location:
// File: src/routes/setup?/seedDatabase.ts
for (const schema of collections) {
await dbAdapter.collection.createModel(schema);
// โ ๏ธ Potential race condition here
}
Suggested Fix:
// Add mutex or serial execution
const results = [];
for (const schema of collections) {
const result = await dbAdapter.collection.createModel(schema);
results.push(result);
// Add small delay to avoid race conditions
await new Promise((resolve) => setTimeout(resolve, 100));
}
Alternative Fix (Better):
// Use batch operation with proper transaction
await dbAdapter.collection.createModels(collections);
// Implement atomic batch creation in MongoCollectionMethods
Issue #2: Vite Cache Invalidation
Problem:
After writePrivateConfig() creates/updates config/private.ts, Viteโs import cache may serve the old version.
Current Workaround:
/setup?/completeSetupreads private.ts directly from filesystem usingfs.readFile()- Bypasses Viteโs import cache with regex parsing
initializeWithFreshConfig()forces fresh import with dynamic import
Better Solution:
- Implement proper Vite HMR invalidation for config files
- Use Viteโs
server.moduleGraph.invalidateModule()API
Flow Diagrams
First-Time Setup (Complete Flow)
Server Restart (Smart Compilation)
Best Practices
For Developers
-
Never manually edit compiled collections (
compiledCollections/)- Always edit source files (
config/collections/) - Let the compilation system handle UUID preservation
- Always edit source files (
-
Donโt delete compiled collections during development
- UUIDs would be regenerated, breaking database references
- Use
git cleancarefully
-
Use content hashing for change detection
- The system automatically detects changes via SHA-256 hash
- No manual intervention needed
For System Administrators
-
Backup compiled collections before migrations
tar -czf compiledCollections.backup.tar.gz compiledCollections/ -
Database migrations preserve UUIDs
- Collection IDs are stored in
_idfield - Never modify
_idin database or compiled files
- Collection IDs are stored in
-
Setup completion is atomic
- If setup fails, system reverts to setup mode
- No partial state left behind
Part III: Testing & CI/CD
Testing Overview
SveltyCMS uses a comprehensive testing strategy to ensure code quality across all environments.
Testing Layers
- โ E2E Tests (Playwright) - Full user workflows, browser automation
- โ Integration Tests - API endpoints, database operations
- โ Unit Tests (Bun) - Components, utilities, functions
- โ CI/CD Automation - GitHub Actions for testing and releases
Test Coverage
- โ Authentication flows (Email, OAuth, 2FA)
- โ User management (CRUD, permissions, roles)
- โ Collection management (Builder, CRUD, relationships)
- โ All 95+ API endpoints tested
- โ UI components and stores
- โ Database operations
Unit Testing with Bun
Running Bun Tests
# Run all tests
bun test
# Run specific test
bun test tests/bun/api/auth.test.ts
# Watch mode
bun test --watch
# With coverage
bun test --coverage
Test Structure
tests/bun/
โโโ api/ # API endpoint tests
โโโ auth/ # Authentication tests
โโโ widgets/ # Widget tests
โโโ mocks/
โ โโโ setup.ts # Preload file (mocks SvelteKit)
โโโ *.test.ts # Various unit tests
Writing Tests
import { describe, it, expect } from 'bun:test';
describe('ContentService', () => {
it('should create content', async () => {
const content = await service.create({
title: 'Test Post'
});
expect(content.title).toBe('Test Post');
});
});
E2E Testing with Playwright
Running Playwright Tests
# Run all tests
npx playwright test
# Specific test
npx playwright test signupfirstuser.spec.ts
# Debug mode
npx playwright test --debug
# UI mode
npx playwright test --ui
Test Files
tests/playwright/
โโโ signupfirstuser.spec.ts
โโโ oauth-signup-firstuser.spec.ts
โโโ login.spec.ts
โโโ user-crud.spec.ts
โโโ collection-builder.spec.ts
โโโ permission-change.spec.ts
GitHub Actions CI/CD
Workflow: Playwright Tests
File: .github/workflows/playwright.yml
Runs comprehensive tests on every push and PR:
name: Playwright and Bun Tests
on:
push:
branches: [main, next]
pull_request:
branches: [main]
workflow_call: {} # Can be called by auto-release
jobs:
test:
strategy:
matrix:
mode: [dev, preview] # Test both modes
steps:
# Start MongoDB service container
- uses: supercharge/mongodb-github-action@1.10.0
with:
mongodb-version: latest
mongodb-username: admin
mongodb-password: admin
# Seed database BEFORE starting server
- run: bun run scripts/seed-cms.js
env:
MONGO_HOST: localhost
MONGO_PORT: 27017
MONGO_DB: SveltyCMS
# Create admin user BEFORE starting server
- run: bun run scripts/create-admin.js
env:
ADMIN_USER: admin
ADMIN_EMAIL: admin@example.com
ADMIN_PASS: Admin123!
# Start server (dev or preview)
- run: bunx vite dev --port 5173 &
if: matrix.mode == 'dev'
# Run tests
- run: bunx playwright test
Workflow: Auto-Release
File: .github/workflows/auto-release.yaml
Automatically releases new versions after tests pass:
name: Semantic Release
on:
push:
branches: [main] # Only release from main
jobs:
test:
uses: ./.github/workflows/playwright.yml # Run tests first
release:
needs: [test] # Only release if tests pass
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for semantic-release
- run: bunx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CI/CD Features
โ
MongoDB Service - Isolated database for testing
โ
Matrix Testing - Tests both dev and preview modes
โ
Automated Setup - Seeds DB + creates admin automatically
โ
Test Gating - Releases only if tests pass
โ
Semantic Versioning - Automatic version bumps based on commits
โ
Artifact Upload - Test reports and videos on failure
Automated Setup Scripts
For CI/CD environments, SveltyCMS provides scripts that replicate the setup wizard.
Script: Seed Database
File: scripts/seed-cms.js
Mimics /setup?/seedDatabase endpoint:
import { writePrivateConfig } from '../src/routes/setup/writePrivateConfig.js';
import { initSystemFromSetup } from '../src/routes/setup/seed.js';
import { getSetupDatabaseAdapter } from '../src/routes/setup/utils.js';
async function main() {
const dbConfig = {
type: 'mongodb',
host: process.env.MONGO_HOST || 'localhost',
port: parseInt(process.env.MONGO_PORT || '27017'),
name: process.env.MONGO_DB || 'SveltyCMS',
user: process.env.MONGO_USER || '',
password: process.env.MONGO_PASS || ''
};
// Write config/private.ts
await writePrivateConfig(dbConfig);
// Connect and seed
const { dbAdapter } = await getSetupDatabaseAdapter(dbConfig);
await initSystemFromSetup(dbAdapter);
await dbAdapter.disconnect();
}
main().catch((err) => {
console.error('โ Seeding failed:', err);
process.exit(1);
});
Usage:
# Local
bun run scripts/seed-cms.js
# CI/CD with environment variables
MONGO_HOST=localhost MONGO_PORT=27017 bun run scripts/seed-cms.js
Script: Create Admin User
File: scripts/create-admin.js
Mimics /setup?/completeSetup endpoint:
import { Auth } from '../src/databases/auth/index.js';
import { getSetupDatabaseAdapter } from '../src/routes/setup/utils.js';
async function main() {
const dbConfig = {
/* same as seed-cms.js */
};
const admin = {
username: process.env.ADMIN_USER || 'admin',
email: process.env.ADMIN_EMAIL || 'admin@example.com',
password: process.env.ADMIN_PASS || 'Admin123!'
};
const { dbAdapter } = await getSetupDatabaseAdapter(dbConfig);
const auth = new Auth(dbAdapter);
try {
await auth.createUser({
...admin,
role: 'admin',
isActive: true
});
console.log('โ
Admin user created!');
} catch (error) {
if (error.message?.includes('duplicate')) {
console.log('โน๏ธ Admin user already exists');
} else {
throw error;
}
}
await dbAdapter.disconnect();
}
main().catch((err) => {
console.error('โ Admin creation failed:', err);
process.exit(1);
});
Usage:
# Local
bun run scripts/create-admin.js
# CI/CD with custom credentials
ADMIN_USER=admin \
ADMIN_EMAIL=admin@example.com \
ADMIN_PASS=SecurePass123! \
bun run scripts/create-admin.js
Script Benefits
โ
No UI required - Perfect for CI/CD
โ
Idempotent - Safe to run multiple times
โ
Environment-driven - Uses environment variables
โ
Reuses setup logic - Imports from actual setup endpoints
โ
Error handling - Graceful failure with exit codes
Part IV: Troubleshooting & Reference
Troubleshooting
Setup wizard loops infinitely
Cause: isSetupCompleteAsync() returns false due to missing users
Fix:
# Check if admin users exist
mongo sveltycms --eval "db.auth_users.find().pretty()"
# If empty, complete setup wizard again
# or manually create admin user via MongoDB shell
Collections not appearing after setup
Cause: seedCollectionsForSetup() failed silently
Fix:
# Check logs for collection seeding errors
tail -f logs/app.log | grep "seedCollections"
# Manually trigger collection initialization
# Restart server with DEBUG=true
UUID changed after recompilation
Cause: Compiled collection was deleted or corrupted
Fix:
# Restore from backup
tar -xzf compiledCollections.backup.tar.gz
# Or manually restore UUID in MongoDB
mongo sveltycms --eval 'db.system_content_structure.find({name: "Posts"})'
# Copy _id, then update compiled file
Summary
This comprehensive guide covers the complete SveltyCMS lifecycle:
โ
Installation - Quick and manual installation methods
โ
First-Time Setup - Wizard-based and automated setup flows
โ
Server Restart - Intelligent recompilation and UUID preservation
โ
Collection Management - UUID assignment and lifecycle
โ
Testing - Unit tests (Bun) and E2E tests (Playwright)
โ
CI/CD - Automated testing and semantic releases
โ
Troubleshooting - Common issues and solutions
Key Highlights
๐ Zero-Restart Setup - System becomes operational without server restart
๐ UUID Preservation - Collections maintain stable IDs across restarts
โก Smart Compilation - Only recompiles changed collections using content hashing
๐งช Comprehensive Testing - 95+ API endpoints, full user workflows
๐ค Automated CI/CD - GitHub Actions for testing and releases
๐ Automated Scripts - seed-cms.js and create-admin.js for CI/CD
โ ๏ธ Known Issue: Collection UUID table creation may have race conditions during seedCollectionsForSetup()
The system is production-ready and fully automated for both local development and CI/CD environments.
Related Documentation
Architecture
- Collection Store Data Flow - How data flows through the collection store
- State Management - System state machine details
- Cache System - Caching strategy and TTLs
API References
- Setup Actions - Complete setup API reference
- Collection API - Collection CRUD operations
- Authentication API - User authentication
Database
- Core Infrastructure - Database adapter system
- MongoDB Methods - MongoDB-specific implementation
Guides
- Complete Workflow Guide - This document (installation, setup, testing, CI/CD)
- Troubleshooting - Common issues and solutions
Quick Reference
Key Files
| File | Purpose | When Modified |
|---|---|---|
vite.config.ts |
Build-time setup detection | Rarely |
src/hooks.server.ts |
Runtime request gatekeeper | When adding middleware |
src/databases/db.ts |
Database initialization | When adding adapters |
src/content/content-manager.ts |
Collection management | When changing collection logic |
src/utils/compilation/compile.ts |
Smart compilation | When changing collection format |
Key Concepts
- Setup Mode: System state when no admin users exist
- UUID Preservation: Collections keep the same ID across restarts
- Smart Compilation: Only recompiles changed collections using content hashing
- Zero-Restart Setup: System becomes operational without server restart
- State Machine: IDLE โ INITIALIZING โ READY โ DEGRADED โ FAILED
Performance Benchmarks
| Operation | Expected Time | Notes |
|---|---|---|
| Vite Startup | 2-5 seconds | Includes TypeScript compilation |
| Database Test | 1-3 seconds | May include driver installation |
| Seed Database | 3-8 seconds | Depends on collection count |
| Complete Setup | 4-6 seconds | Includes full system init |
| Total Setup | 10-25 seconds | Excluding user input |
| Collection Compile | 50-200ms per file | With UUID preservation |
| Server Restart | 3-5 seconds | To READY state |