Documentation

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, and TESTING_GUIDE.md.old


Table of Contents

Part I: Installation & Setup

  1. Prerequisites
  2. Quick Installation
  3. Manual Installation
  4. First-Time Setup Flow
  5. Post-Installation Configuration

Part II: System Architecture

  1. Visual Overview
  2. Server Restart Flow
  3. Collection UUID Management

    See Compilation Pipeline for detailed architecture.

  4. Key Components
  5. State Machine
  6. Compilation Pipeline

Part III: Testing & CI/CD

  1. Testing Overview
  2. Unit Testing with Bun
  3. E2E Testing with Playwright
  4. GitHub Actions CI/CD
  5. Automated Setup Scripts

Part IV: Troubleshooting & Reference

  1. Known Issues
  2. Troubleshooting
  3. Best Practices
  4. Quick 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)

MariaDB/MySQL (alternative)


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:

  1. Database Configuration

    • Choose: MongoDB, MariaDB, or PostgreSQL
    • Enter connection details
    • Test connection automatically
  2. Database Driver Installation

    • Automatically installs required drivers
    • Detects your package manager
    • Handles dependencies
  3. System Language Selection

    • Choose default language
    • Configures internationalization
  4. Initial Data Seeding

    • Seeds system settings (53 keys)
    • Creates default theme
    • Sets up base configuration
  5. Admin User Creation

    • Set admin email
    • Create secure password
    • Generate session secrets
  6. 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

graph TB subgraph "First-Time Setup" A1[Fresh Install] -->|No private.ts| A2[Vite: Setup Mode] A2 --> A3[Create Blank Config] A3 --> A4[Open /setup Wizard] A4 --> A5[User: Enter DB Config] A5 --> A6[Action: testDatabase] A6 -->|โœ“ Valid| A7[User: Select Language] A7 --> A8[Action: seedDatabase] A8 --> A9[Write Credentials] A8 --> A10[Seed Settings/Themes] A8 --> A11[Create Collections] A12[User: Admin Form] --> A13[Action: completeSetup] A13 --> A14[Create Admin + Session] A13 --> A15[Init Global System] A13 --> A16[ContentManager Init] A16 --> A17[READY State] end subgraph "Server Restart" B1[Server Start] -->|private.ts exists| B2[Vite: Normal Mode] B2 --> B3[Scan Compiled Collections] B3 --> B4{For Each Collection} B4 --> B5{Hash Changed?} B5 -->|No| B6[Skip - Preserve UUID] B5 -->|Yes| B7[Recompile - Keep UUID] B6 --> B8[First Request] B7 --> B8 B8 --> B9[handleSystemState] B9 --> B10[dbInitPromise] B10 --> B11[Connect Database] B11 --> B12[Load Settings] B12 --> B13[Init Services] B13 --> B14[READY State] end A17 -.->|Restart Server| B1 style A1 fill:#f0f0f0,stroke:#333,stroke-width:3px style A4 fill:#e0e0e0,stroke:#333,stroke-width:2px style A8 fill:#e0e0e0,stroke:#333,stroke-width:2px style A13 fill:#e0e0e0,stroke:#333,stroke-width:2px style A17 fill:#d0d0d0,stroke:#333,stroke-width:4px style B1 fill:#f0f0f0,stroke:#333,stroke-width:3px style B7 fill:#e0e0e0,stroke:#333,stroke-width:2px style B14 fill:#d0d0d0,stroke:#333,stroke-width:4px

First-Time Setup Architecture

graph TB A[Vite Startup] -->|No private.ts| B[setupWizardPlugin] B --> C[Create Blank private.ts] B --> D[Compile Collections] B --> E[Open /setup in Browser] E --> F[User: DB Config] F --> G[Action: testDatabase] G -->|Success| H[User: System Language] H --> I[Action: seedDatabase] I --> J[Write private.ts] I --> K[Seed Settings] I --> L[Seed Themes] I --> M[Seed Collections] N --> O[Action: completeSetup] O --> P[Create Admin User] O --> Q[Initialize Global System] O --> R[Initialize ContentManager] O --> S[Set Session Cookie] S --> T[Redirect to CMS] style A fill:#f0f0f0,stroke:#333,stroke-width:3px style E fill:#e0e0e0,stroke:#333,stroke-width:2px style I fill:#e0e0e0,stroke:#333,stroke-width:2px style O fill:#e0e0e0,stroke:#333,stroke-width:2px style T fill:#d0d0d0,stroke:#333,stroke-width:4px

Server Restart Architecture

graph TB A[Vite Startup] -->|private.ts exists| B[cmsWatcherPlugin] B --> C[Scan Compiled Collections] C --> D{For Each Collection} D --> E{Hash Changed?} E -->|No| F[Skip Compilation] E -->|Yes| G[Recompile] F --> H[Preserve UUID] G --> H H --> I[First HTTP Request] I --> J[handleSystemState] J --> K[dbInitPromise] K --> L[Load private.ts] K --> M[Connect to Database] K --> N[Load Settings] K --> O[Initialize Services] O --> P[READY State] P --> Q[ContentManager Auto-Init] Q --> R[Register Collections] style A fill:#f0f0f0,stroke:#333,stroke-width:3px style B fill:#e0e0e0,stroke:#333,stroke-width:2px style G fill:#e0e0e0,stroke:#333,stroke-width:2px style H fill:#d0d0d0,stroke:#333,stroke-width:3px style P fill:#d0d0d0,stroke:#333,stroke-width:4px

First-Time Setup Flow

Phase 1: Vite Startup (Build Time)

File: vite.config.ts

sequenceDiagram participant Vite participant FS as Filesystem participant Browser Note over Vite: Startup Check Vite->>FS: Check config/private.ts exists? FS-->>Vite: โŒ Not found Note over Vite: Setup Mode Activated Vite->>FS: Create blank private.ts Vite->>FS: Create placeholder collections Vite->>FS: Compile any existing collections Note over Vite: Open Setup Wizard Vite->>Browser: Open http://localhost:5173/setup Note over Browser: User sees setup wizard

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

flowchart TB A[Incoming Request] --> B{handleSystemState} B -->|System: IDLE| C{handleSetup} C -->|Check Config| D{private.ts valid?} D -->|No DB creds| E[isSetupComplete = false] E --> F{Path check} F -->|/setup| G[Allow Request] F -->|Other paths| H[Redirect to /setup] C -->|Check Database| I{hasAdminUsers?} I -->|No| E I -->|Yes| J[Allow Request - Setup Complete] style E fill:#d0d0d0,stroke:#333,stroke-width:3px style G fill:#e0e0e0,stroke:#333,stroke-width:2px style J fill:#e0e0e0,stroke:#333,stroke-width:2px

Phase 3: Setup GUI Interaction

File: src/routes/setup/+page.svelte

stateDiagram-v2 [*] --> database-config: Step 1 database-config --> DatabaseTest: User fills DB form DatabaseTest --> SystemLanguage: Test passed โœ“ SystemLanguage --> SeedData: Language selected SeedData --> AdminUser: Database seeded โœ“ AdminUser --> Complete: Admin form submitted Complete --> [*]: Redirect to CMS DatabaseTest --> database-config: Test failed โœ— note right of DatabaseTest POST /setup?/testDatabase - Validates connection - Installs drivers if needed end note note right of SeedData POST /setup?/seedDatabase - Writes private.ts - Seeds settings/themes (background) - Creates collections (background) - Polling: /api/system/health end note note right of Complete POST /setup?/completeSetup - Creates admin user - Initializes system - Sets session cookie end note

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)

sequenceDiagram participant Client as Browser participant Setup as /setup Actions participant PM as Package Manager participant Mongoose participant DB as MongoDB Client->>Setup: POST {host, port, name, user, pass} Note over Setup: Check Driver Setup->>Mongoose: Try import mongoose alt Driver Missing Setup->>PM: Detect package manager (bun/npm/pnpm/yarn) Setup->>PM: Install mongoose alt Permission Error PM-->>Setup: EACCES โœ— Setup-->>Client: {success: false, manualCommand: "..."} else Success PM-->>Setup: Installation complete โœ“ end end Note over Setup: Build Connection Setup->>Setup: buildConnectionString() Note over Setup: Test Connection Setup->>DB: Connect with 15s timeout alt Success DB-->>Setup: Connected โœ“ Setup->>DB: Authenticate DB-->>Setup: Auth OK โœ“ Setup->>DB: Get database stats DB-->>Setup: {collections: 0, dataSize: 0} Setup-->>Client: {success: true, details: {...}} else Failure DB-->>Setup: Connection error Setup-->>Client: {success: false, error: "..."} end
POST /setup?/testDatabase
Body: {
  type: "mongodb",
  host: "localhost",
  port: 27017,
  name: "sveltycms",
  user: "admin",
  password: "secret123"
}

Process:

  1. Detects package manager (bun/npm/pnpm/yarn)
  2. Installs MongoDB driver if missing (mongoose)
  3. Builds connection string
  4. Tests connection with 15s timeout
  5. 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):

  1. Race Condition: Multiple createModel() calls execute in parallel without proper locking
  2. Mongoose Model Registry: Mongoose may be caching models by name, causing conflicts
  3. 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?/completeSetup reads private.ts directly from filesystem using fs.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)

sequenceDiagram participant V as Vite participant H as Hooks participant U as User (Browser) participant API as Setup API participant DB as Database participant CM as ContentManager V->>V: Check private.ts (missing) V->>V: Create blank private.ts V->>V: Compile collections V->>U: Open /setup in browser U->>**API Call**: `POST /setup?/testDatabase` (SvelteKit Server Action) API->>DB: Test connection DB-->>API: Success API-->>U: Connection valid U->>API: POST /setup?/seedDatabase API->>API: Write private.ts (with credentials) API->>DB: Seed settings API->>DB: Seed themes API->>DB: Seed collections (create models) API-->>U: Seed complete + firstCollection U->>API: POST /setup?/completeSetup API->>DB: Create admin user + session API->>API: initializeWithFreshConfig() API->>CM: Initialize ContentManager API->>API: Invalidate caches API-->>U: Setup complete + redirect + session cookie U->>H: GET /en/Collections/Posts H->>H: handleSetup: isSetupComplete() โ†’ true H->>CM: Load collection CM-->>U: Render collection view

Server Restart (Smart Compilation)

sequenceDiagram participant V as Vite participant FS as Filesystem participant CM as Compilation participant DB as Database V->>V: Check private.ts (exists + valid) V->>CM: Trigger intelligent compilation CM->>FS: Scan compiledCollections/ FS-->>CM: {path โ†’ {jsPath, uuid, hash}} CM->>FS: Scan config/collections/ FS-->>CM: List of .ts files loop For each collection CM->>CM: Calculate content hash alt Hash matches CM->>CM: SKIP (no changes) else Hash differs CM->>CM: RECOMPILE CM->>CM: PRESERVE UUID CM->>FS: Write updated .js file end end CM->>V: Compilation complete V->>DB: Initialize database connection V->>CM: Initialize ContentManager CM->>DB: Register collection models

Best Practices

For Developers

  1. Never manually edit compiled collections (compiledCollections/)

    • Always edit source files (config/collections/)
    • Let the compilation system handle UUID preservation
  2. Donโ€™t delete compiled collections during development

    • UUIDs would be regenerated, breaking database references
    • Use git clean carefully
  3. Use content hashing for change detection

    • The system automatically detects changes via SHA-256 hash
    • No manual intervention needed

For System Administrators

  1. Backup compiled collections before migrations

    tar -czf compiledCollections.backup.tar.gz compiledCollections/
  2. Database migrations preserve UUIDs

    • Collection IDs are stored in _id field
    • Never modify _id in database or compiled files
  3. 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

API References

Database

Guides


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
architectureinitializationsetupworkflowcollectionsinstallationtestingci-cd