### Install dependencies
Source: https://svelteforge.dashboardpack.com/docs/getting-started
Install all required project dependencies using pnpm.
```bash
pnpm install
```
--------------------------------
### Start the development server
Source: https://svelteforge.dashboardpack.com/docs/getting-started
Launch the SvelteKit development server to view the application locally.
```bash
pnpm dev
```
--------------------------------
### Build and Run Production Server
Source: https://svelteforge.dashboardpack.com/docs/deployment
Commands to compile the SvelteKit application and start the production server.
```bash
# Create the production build
pnpm build
# Run the production server
node build/index.js
```
--------------------------------
### Manage Node.js Process with PM2 on VPS
Source: https://svelteforge.dashboardpack.com/docs/deployment
Install and configure PM2 to keep the SvelteKit application running on a VPS.
```bash
# Example: PM2 process manager on a VPS
npm install -g pm2
pm2 start build/index.js --name svelteforge
pm2 save
pm2 startup
```
--------------------------------
### Launch Drizzle Studio
Source: https://svelteforge.dashboardpack.com/docs/database
Starts the browser-based GUI for inspecting and editing the SQLite database.
```bash
pnpm db:studio
```
--------------------------------
### Install D3 dependencies
Source: https://svelteforge.dashboardpack.com/docs/analytics
Install the necessary D3 modules and their corresponding TypeScript definitions for data visualization.
```bash
pnpm add d3-scale d3-array d3-shape
pnpm add -D @types/d3-scale @types/d3-array @types/d3-shape
```
--------------------------------
### Dockerfile for SvelteForge Admin
Source: https://svelteforge.dashboardpack.com/docs/deployment
A multi-stage Dockerfile that installs dependencies, builds the SvelteKit application, and sets up the production environment with SQLite support.
```dockerfile
# Stage 1: Install dependencies
FROM node:20-alpine AS deps
RUN apk add --no-cache python3 make g++
WORKDIR /app
RUN corepack enable pnpm
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
# Stage 2: Build the SvelteKit application
FROM node:20-alpine AS builder
WORKDIR /app
RUN corepack enable pnpm
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm build
# Stage 3: Production image
FROM node:20-alpine AS runner
RUN apk add --no-cache python3 make g++
WORKDIR /app
RUN corepack enable pnpm
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod
COPY --from=builder /app/build ./build
COPY --from=builder /app/drizzle ./drizzle
# Create data directory for SQLite
RUN mkdir -p /app/data
ENV NODE_ENV=production
ENV PORT=3000
ENV HOST=0.0.0.0
ENV DATABASE_URL=/app/data/svelteforge.db
EXPOSE 3000
CMD ["node", "build/index.js"]
```
--------------------------------
### GET /sitemap.xml
Source: https://svelteforge.dashboardpack.com/docs/api-reference
Retrieves an auto-generated XML sitemap for SEO purposes.
```APIDOC
## GET /sitemap.xml
### Description
Returns all published page URLs in standard XML sitemap format.
### Method
GET
### Endpoint
/sitemap.xml
```
--------------------------------
### GET /api/search
Source: https://svelteforge.dashboardpack.com/docs/routing
The search endpoint powers the command palette by querying users, pages, and notifications based on a search query string.
```APIDOC
## GET /api/search
### Description
Queries users, pages, and notifications in parallel based on a search term to power the command palette.
### Method
GET
### Endpoint
/api/search
### Parameters
#### Query Parameters
- **q** (string) - Required - The search query string to filter results.
```
--------------------------------
### Search API Endpoint Request and Response
Source: https://svelteforge.dashboardpack.com/docs/api-reference
Demonstrates the structure of the GET /api/search request and the corresponding JSON response.
```http
// Request
GET /api/search?q=admin
// Response
{
"results": [
{
"title": "Admin User",
"description": "admin@svelteforge.dev",
"url": "/users",
"category": "Users",
"icon": "users"
},
{
"title": "Admin Dashboard Settings",
"description": "Configure dashboard preferences",
"url": "/content/admin-dashboard-settings",
"category": "Pages",
"icon": "file-text"
}
]
}
```
--------------------------------
### GET /api/search
Source: https://svelteforge.dashboardpack.com/docs/api-reference
Performs a full-text search across users, pages, and notifications.
```APIDOC
## GET /api/search
### Description
Performs a full-text search across users, pages, and notifications. Returns categorized results with icons.
### Method
GET
### Endpoint
/api/search
### Parameters
#### Query Parameters
- **q** (string) - Required - The search query string.
### Request Example
GET /api/search?q=admin
### Response
#### Success Response (200)
- **results** (array) - A list of search result objects.
#### Response Example
{
"results": [
{
"title": "Admin User",
"description": "admin@svelteforge.dev",
"url": "/users",
"category": "Users",
"icon": "users"
},
{
"title": "Admin Dashboard Settings",
"description": "Configure dashboard preferences",
"url": "/content/admin-dashboard-settings",
"category": "Pages",
"icon": "file-text"
}
]
}
```
--------------------------------
### Deploy to Fly.io via CLI
Source: https://svelteforge.dashboardpack.com/docs/deployment
Launch a new application, create a persistent volume, and deploy to Fly.io.
```bash
# Fly.io deployment
fly launch
fly volumes create svelteforge_data --size 1 --region ord
fly deploy
```
--------------------------------
### Clone the repository
Source: https://svelteforge.dashboardpack.com/docs/getting-started
Download the project source code and navigate into the directory.
```bash
git clone https://github.com/your-org/svelteforge-admin.git
cd svelteforge-admin
```
--------------------------------
### Deploy to Railway via CLI
Source: https://svelteforge.dashboardpack.com/docs/deployment
Initialize a project, configure a persistent volume, and deploy to Railway.
```bash
# Railway CLI deployment
railway init
railway volume add --mount /app/data
railway up
```
--------------------------------
### Seed sample data
Source: https://svelteforge.dashboardpack.com/docs/getting-started
Populate the database with initial sample data for testing.
```bash
pnpm db:seed
```
--------------------------------
### Initialize the database
Source: https://svelteforge.dashboardpack.com/docs/getting-started
Push the Drizzle ORM schema to create the local SQLite database file.
```bash
pnpm db:push
```
--------------------------------
### Create Route Directory
Source: https://svelteforge.dashboardpack.com/docs/routing
Command to initialize a new route directory within the protected (app) layout.
```bash
mkdir -p src/routes/\(app\)/reports
```
--------------------------------
### Build and Run Commands
Source: https://svelteforge.dashboardpack.com/docs/deployment
Commands to build the Docker image and run the container with a persistent volume for the SQLite database.
```bash
# Build the Docker image
docker build -t svelteforge-admin .
# Run with a persistent volume for SQLite
docker run -p 3000:3000 -v ./data:/app/data svelteforge-admin
```
--------------------------------
### Configure OAuth Providers
Source: https://svelteforge.dashboardpack.com/docs/authentication
Initializes Arctic OAuth clients based on environment variables. Returns null for providers missing credentials to ensure graceful degradation.
```typescript
// src/lib/server/oauth.ts
import * as arctic from "arctic";
import { env } from "$env/dynamic/private";
function getBaseUrl(): string {
return env.ORIGIN || "http://localhost:5173";
}
export const google =
env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET
? new arctic.Google(
env.GOOGLE_CLIENT_ID,
env.GOOGLE_CLIENT_SECRET,
`${getBaseUrl()}/login/google/callback`
)
: null;
export const github =
env.GITHUB_CLIENT_ID && env.GITHUB_CLIENT_SECRET
? new arctic.GitHub(
env.GITHUB_CLIENT_ID,
env.GITHUB_CLIENT_SECRET,
`${getBaseUrl()}/login/github/callback`
)
: null;
export function getEnabledProviders(): string[] {
const providers: string[] = [];
if (google) providers.push("google");
if (github) providers.push("github");
return providers;
}
```
--------------------------------
### Structure test files by route co-location
Source: https://svelteforge.dashboardpack.com/docs/testing
Demonstrates the recommended directory structure where test files are placed alongside their corresponding route files.
```text
src/routes/(app)/users/
+page.svelte # UI component (Svelte 5)
+page.server.ts # Server load + form actions
users.test.ts # Unit tests for +page.server.ts
src/routes/(app)/settings/
+page.svelte
+page.server.ts
settings.test.ts
```
--------------------------------
### Add shadcn-svelte components via CLI
Source: https://svelteforge.dashboardpack.com/docs/project-structure
Use the shadcn-svelte CLI to add or update UI primitives in the project. Avoid manual edits to files in the src/lib/components/ui/ directory.
```bash
npx shadcn-svelte@latest add button
npx shadcn-svelte@latest add dialog
npx shadcn-svelte@latest add dropdown-menu
```
--------------------------------
### SvelteKit Login Form Action
Source: https://svelteforge.dashboardpack.com/docs/authentication
Implements a server-side login flow with input validation, password verification, and session management.
```typescript
// src/routes/(auth)/login/+page.server.ts
export const actions: Actions = {
default: async ({ request, cookies, getClientAddress }) => {
const formData = await request.formData();
const username = formData.get("username");
const password = formData.get("password");
// ... validation ...
const existingUser = await db.query.users.findFirst({
where: eq(users.username, username.toLowerCase()),
});
if (!existingUser) {
return fail(400, { message: "Incorrect username or password" });
}
const validPassword = await verify(existingUser.passwordHash, password, {
memoryCost: 19456, timeCost: 2, outputLen: 32, parallelism: 1,
});
if (!validPassword) {
return fail(400, { message: "Incorrect username or password" });
}
const token = generateSessionToken();
const session = await createSession(token, existingUser.id, {
userAgent: request.headers.get("user-agent"),
ipAddress: getClientAddress(),
});
setSessionCookie(cookies, token, session.expiresAt);
redirect(302, "/");
},
};
```
--------------------------------
### Configure Adapter-Node
Source: https://svelteforge.dashboardpack.com/docs/deployment
Configuration for the SvelteKit adapter-node in svelte.config.js to define output directories and compression settings.
```javascript
// svelte.config.js
import adapter from "@sveltejs/adapter-node";
export default {
kit: {
adapter: adapter({
// Output directory (default: "build")
out: "build",
// Precompress static assets with gzip and brotli
precompress: false,
// Environment variable for port (default: "PORT")
envPrefix: "",
}),
},
};
```
--------------------------------
### Initialize Drizzle ORM with SQLite
Source: https://svelteforge.dashboardpack.com/docs/database
Configures the database connection using better-sqlite3 and enables WAL mode for concurrent read performance. This file must reside in src/lib/server/ to prevent client-side exposure.
```typescript
// src/lib/server/db/index.ts
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
import * as schema from "./schema.js";
const dbPath = process.env.DATABASE_URL || "svelteforge.db";
const sqlite = new Database(dbPath);
sqlite.pragma("journal_mode = WAL");
export const db = drizzle(sqlite, { schema });
```
--------------------------------
### Implement Full Authentication Flow Test
Source: https://svelteforge.dashboardpack.com/docs/testing
Demonstrates a complete user journey including registration, dashboard verification, logout, and re-login.
```typescript
import { test, expect } from "@playwright/test";
test("user can register, login, and access dashboard", async ({ page }) => {
// Register a new account
await page.goto("/register");
await page.fill('input[name="name"]', "Test User");
await page.fill('input[name="email"]', "test@example.com");
await page.fill('input[name="username"]', "testuser");
await page.fill('input[name="password"]', "password123");
await page.click('button[type="submit"]');
// Should redirect to dashboard
await expect(page).toHaveURL("/");
await expect(page.locator("text=Dashboard")).toBeVisible();
// Logout
await page.goto("/logout");
// Login with the same credentials
await page.goto("/login");
await page.fill('input[name="username"]', "testuser");
await page.fill('input[name="password"]', "password123");
await page.click('button[type="submit"]');
// Should be back on the dashboard
await expect(page).toHaveURL("/");
});
```
--------------------------------
### Initialize GitHub OAuth
Source: https://svelteforge.dashboardpack.com/docs/api-reference
Creates an authorization URL for GitHub OAuth if the provider is configured.
```typescript
import { github } from "$lib/server/oauth.js";
if (github) {
const url = github.createAuthorizationURL(state, {
scopes: ["user:email"],
});
}
```
--------------------------------
### Configure Drizzle Kit
Source: https://svelteforge.dashboardpack.com/docs/database
Defines the database schema path, migration output directory, and SQLite credentials.
```typescript
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/lib/server/db/schema.ts",
out: "./drizzle",
dialect: "sqlite",
dbCredentials: {
url: "svelteforge.db",
},
});
```
--------------------------------
### Backup SQLite Database
Source: https://svelteforge.dashboardpack.com/docs/deployment
Methods for creating consistent backups of an SQLite database running in WAL mode.
```bash
# Method 1: SQLite backup command (recommended — creates a clean copy)
sqlite3 svelteforge.db ".backup /backups/svelteforge-$(date +%Y%m%d).db"
# Method 2: Copy all WAL files together
cp svelteforge.db svelteforge.db-wal svelteforge.db-shm /backups/
```
--------------------------------
### Enable View Transitions
Source: https://svelteforge.dashboardpack.com/docs/routing
Uses the onNavigate lifecycle hook to implement smooth cross-fade animations between pages.
```typescript
```
--------------------------------
### Implement Svelte 5 reactive patterns for user management
Source: https://svelteforge.dashboardpack.com/docs/user-management
Uses $state for tracking search and pagination inputs, and $derived for reactive filtering and slicing of user data.
```svelte
// Svelte 5 reactive patterns in the users page
let search = $state('');
let currentPage = $state(1);
let pageSize = $state(10);
let filteredUsers = $derived(
users.filter((u) =>
u.name.toLowerCase().includes(search.toLowerCase()) ||
u.email.toLowerCase().includes(search.toLowerCase())
)
);
let paginatedUsers = $derived(
filteredUsers.slice((currentPage - 1) * pageSize, currentPage * pageSize)
);
```
--------------------------------
### Initialize Google OAuth
Source: https://svelteforge.dashboardpack.com/docs/api-reference
Creates an authorization URL for Google OAuth if the provider is configured.
```typescript
import { google } from "$lib/server/oauth.js";
if (google) {
const url = google.createAuthorizationURL(state, codeVerifier, {
scopes: ["openid", "profile", "email"],
});
}
```
--------------------------------
### Reactive state with Svelte 5 runes
Source: https://svelteforge.dashboardpack.com/docs
Demonstrates the use of $state, $derived, and $effect runes to manage component reactivity and side effects.
```svelte
```
--------------------------------
### Parse User-Agent String
Source: https://svelteforge.dashboardpack.com/docs/api-reference
Extracts browser, OS, and device information from a raw user-agent string.
```typescript
import { parseUserAgent } from "$lib/utils/user-agent.js";
const info = parseUserAgent(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
);
// => { browser: "Chrome", os: "macOS", device: "Desktop" }
```
--------------------------------
### Update shadcn-svelte components
Source: https://svelteforge.dashboardpack.com/docs/components
Use the CLI to update components to the latest version while preserving theme tokens. Avoid manual edits to ensure compatibility with future updates.
```bash
npx shadcn-svelte@latest add
```
--------------------------------
### Test SvelteKit form actions
Source: https://svelteforge.dashboardpack.com/docs/testing
Uses Vitest or similar test runners to verify form action logic, including successful user creation and authorization enforcement for non-admin roles.
```javascript
describe("create action", () => {
it("creates a new user when admin submits valid data", async () => {
// Arrange: create an admin user
const admin = createTestUser(testDb, { role: "admin" });
const formData = createFormData({
name: "New User",
email: "new@example.com",
username: "newuser",
password: "securepass123",
role: "editor",
});
// Act: call the form action
const result = await actions.create({
request: createMockRequest(formData),
locals: createMockLocals({ user: admin }),
}) as any;
// Assert: check the result
expect(result.success).toBe(true);
// Assert: verify database state
const users = testDb.select().from(usersTable).all();
expect(users).toHaveLength(2); // admin + new user
expect(users[1].email).toBe("new@example.com");
expect(users[1].role).toBe("editor");
});
it("rejects creation when user is not admin", async () => {
const viewer = createTestUser(testDb, { role: "viewer" });
const formData = createFormData({
name: "Hacker",
email: "hack@example.com",
username: "hacker",
password: "password123",
role: "admin",
});
const result = await actions.create({
request: createMockRequest(formData),
locals: createMockLocals({ user: viewer }),
}) as any;
// Should return 403 failure
expect(result.status).toBe(403);
// Database should only have the original viewer
const users = testDb.select().from(usersTable).all();
expect(users).toHaveLength(1);
});
});
```
--------------------------------
### Define App Settings Table
Source: https://svelteforge.dashboardpack.com/docs/database
Key-value store schema for application configuration using the key as the primary identifier.
```typescript
export const appSettings = sqliteTable("app_settings", {
key: text("key").primaryKey(),
value: text("value").notNull(),
updatedAt: integer("updated_at", { mode: "timestamp" })
.notNull()
.$defaultFn(() => new Date()),
});
```
--------------------------------
### Create mock locals
Source: https://svelteforge.dashboardpack.com/docs/testing
Generates an object matching SvelteKit's App.Locals interface for use in load functions and form actions.
```typescript
const locals = createMockLocals({
user: { id: "abc", role: "admin", name: "Admin" },
session: { id: "sess123", expiresAt: Date.now() + 86400000 },
});
```
--------------------------------
### Configure Playwright for SvelteKit
Source: https://svelteforge.dashboardpack.com/docs/testing
Defines the web server command and port for the production build in playwright.config.ts.
```typescript
// playwright.config.ts
import { defineConfig } from "@playwright/test";
export default defineConfig({
webServer: {
command: "pnpm build && pnpm preview",
port: 4173,
},
testDir: "e2e",
});
```
--------------------------------
### Schedule Automated Backups
Source: https://svelteforge.dashboardpack.com/docs/deployment
Cron job configuration for performing daily database backups at 3 AM.
```bash
# Daily backup at 3 AM
0 3 * * * sqlite3 /app/data/svelteforge.db ".backup /backups/svelteforge-$(date +\%Y\%m\%d).db"
```
--------------------------------
### Implement SvelteKit Server Handle Hook
Source: https://svelteforge.dashboardpack.com/docs/authentication
Handles session validation and metadata updates on every incoming request.
```typescript
// src/hooks.server.ts
export const handle: Handle = async ({ event, resolve }) => {
const token = event.cookies.get(SESSION_COOKIE_NAME);
if (!token) {
event.locals.user = null;
event.locals.session = null;
return resolve(event);
}
const { session, user } = await validateSession(token);
if (session) {
// Refresh cookie with current expiresAt (handles auto-extension)
setSessionCookie(event.cookies, token, session.expiresAt);
// Update session metadata on every request
const ua = event.request.headers.get("user-agent");
const ip = event.getClientAddress();
await db
.update(sessions)
.set({ userAgent: ua, ipAddress: ip })
.where(eq(sessions.id, session.id));
} else {
deleteSessionCookie(event.cookies);
}
event.locals.user = user;
event.locals.session = session;
return resolve(event);
};
```
--------------------------------
### Load Enabled OAuth Providers
Source: https://svelteforge.dashboardpack.com/docs/authentication
SvelteKit server load function that checks for existing sessions and provides the list of enabled OAuth providers to the frontend.
```typescript
// src/routes/(auth)/login/+page.server.ts
export const load: PageServerLoad = async ({ locals }) => {
if (locals.user) redirect(302, "/");
return {
enabledProviders: getEnabledProviders(),
};
};
```
--------------------------------
### SvelteKit Route Group Structure
Source: https://svelteforge.dashboardpack.com/docs/getting-started
Visual representation of the project's file-based routing, where directories in parentheses organize layouts without affecting URL paths.
```text
src/routes/
(app)/ # Protected routes — requires authentication
dashboard/ # Main dashboard with analytics
users/ # User management CRUD
content/ # CMS pages
analytics/ # Charts and data visualization
notifications/
settings/
roles/
database/
(auth)/ # Public auth routes — login, register, OAuth callbacks
login/
register/
forgot-password/
reset-password/
(public)/ # Public pages — no auth required
pricing/
docs/ # Documentation (you are here)
api/ # API endpoints
logout/ # Server-only logout action
```
--------------------------------
### Create in-memory test database
Source: https://svelteforge.dashboardpack.com/docs/testing
Initializes a fresh SQLite database in memory with the required schema for each test run.
```typescript
// test-utils.ts
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
const SCHEMA_SQL = `
CREATE TABLE users (
id TEXT PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
username TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
name TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'viewer',
avatar_url TEXT,
created_at INTEGER DEFAULT (unixepoch()),
updated_at INTEGER DEFAULT (unixepoch())
);
CREATE TABLE sessions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id),
expires_at INTEGER NOT NULL,
user_agent TEXT,
ip_address TEXT,
created_at INTEGER DEFAULT (unixepoch())
);
-- ... remaining tables (pages, notifications, appSettings, etc.)
`;
export function createTestDb() {
const sqlite = new Database(":memory:");
sqlite.pragma("journal_mode = WAL");
sqlite.exec(SCHEMA_SQL);
return drizzle(sqlite);
}
```
--------------------------------
### Query Database with Drizzle ORM
Source: https://svelteforge.dashboardpack.com/docs/api-reference
Demonstrates SQL-like query building and relational API usage with the Drizzle ORM instance.
```typescript
import { db } from "$lib/server/db/index.js";
import { users } from "$lib/server/db/schema.js";
import { eq } from "drizzle-orm";
// SQL-like query builder
const allUsers = await db.select().from(users);
// Relational query API
const user = await db.query.users.findFirst({
where: eq(users.email, "admin@svelteforge.dev"),
});
```
--------------------------------
### Define App Locals Types
Source: https://svelteforge.dashboardpack.com/docs/routing
Extends the SvelteKit App namespace to include user and session information in event.locals.
```typescript
// src/app.d.ts
declare global {
namespace App {
interface Locals {
user: SessionUser | null;
session: Session | null;
}
}
}
```
--------------------------------
### Page Status Lifecycle
Source: https://svelteforge.dashboardpack.com/docs/content-management
Visual representation of the page status transition flow.
```text
Draft --> Published --> Archived
```
--------------------------------
### Mock server database module
Source: https://svelteforge.dashboardpack.com/docs/testing
Intercepts database imports using vitest and dynamic imports to ensure tests use the in-memory instance instead of the development database.
```typescript
import { describe, it, expect, vi, beforeEach } from "vitest";
import { createTestDb, createTestUser, createMockLocals } from "$lib/test-utils.js";
let testDb: ReturnType;
// Step 1: Set up the mock BEFORE importing the server module
vi.mock("$lib/server/db/index.js", () => ({
get db() {
return testDb;
},
}));
// Step 2: Dynamically import the module AFTER the mock is in place
const { load, actions } = await import("./+page.server.js");
describe("Users page", () => {
beforeEach(() => {
// Fresh database for every test
testDb = createTestDb();
});
// ... tests ...
});
```
--------------------------------
### Pattern Matching with LIKE
Source: https://svelteforge.dashboardpack.com/docs/database
Performs a case-insensitive search across name and email fields using SQL LIKE.
```javascript
import { sql, or } from "drizzle-orm";
const pattern = `%${searchQuery}%`;
const results = await db
.select({ id: users.id, name: users.name })
.from(users)
.where(or(
sql`${users.name} LIKE ${pattern}`,
sql`${users.email} LIKE ${pattern}`
))
.limit(10);
```
--------------------------------
### Create Session
Source: https://svelteforge.dashboardpack.com/docs/authentication
Persists a new session in the database with associated metadata.
```typescript
export async function createSession(
token: string,
userId: string,
metadata?: { userAgent?: string | null; ipAddress?: string | null }
): Promise {
const sessionId = hashToken(token);
const expiresAt = Date.now() + SESSION_LIFETIME_MS; // 30 days
const session: Session = {
id: sessionId,
userId,
expiresAt,
userAgent: metadata?.userAgent ?? null,
ipAddress: metadata?.ipAddress ?? null,
createdAt: new Date(),
};
await db.insert(sessions).values(session);
return session;
}
```
--------------------------------
### Implement Profile Update Form Action
Source: https://svelteforge.dashboardpack.com/docs/settings
Handles profile updates via SvelteKit form actions, including server-side validation and email uniqueness checks using Drizzle ORM.
```javascript
// Profile update form action (simplified)
profile: async ({ request, locals }) => {
if (!locals.user) return fail(401, { message: "Unauthorized" });
const formData = await request.formData();
const name = formData.get("name")?.toString().trim();
const email = formData.get("email")?.toString().trim().toLowerCase();
const avatarUrl = formData.get("avatarUrl")?.toString().trim() || null;
// Validate required fields
if (!name || !email) {
return fail(400, { message: "Name and email are required" });
}
// Check email uniqueness (exclude current user)
const existing = await db.query.users.findFirst({
where: and(eq(users.email, email), ne(users.id, locals.user.id)),
});
if (existing) {
return fail(400, { message: "Email is already in use" });
}
await db.update(users)
.set({ name, email, avatarUrl })
.where(eq(users.id, locals.user.id));
return { success: true, message: "Profile updated" };
}
```
--------------------------------
### Create a test user
Source: https://svelteforge.dashboardpack.com/docs/testing
Inserts a user into the test database with defaults that can be overridden via the second argument.
```typescript
const user = createTestUser(testDb, {
role: "admin",
email: "admin@test.com",
username: "admin",
});
// Defaults if not overridden:
// - id: random generated ID
// - name: "Test User"
// - email: "test@example.com"
// - username: "testuser"
// - password: hashed "password123"
// - role: "viewer"
```
--------------------------------
### Docker Compose Configuration
Source: https://svelteforge.dashboardpack.com/docs/deployment
Configuration for running the application with persistent volumes and environment variables.
```yaml
version: "3.8"
services:
svelteforge:
build: .
ports:
- "3000:3000"
volumes:
- ./data:/app/data
environment:
- DATABASE_URL=/app/data/svelteforge.db
- ORIGIN=https://admin.example.com
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
- GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
restart: unless-stopped
```
--------------------------------
### Implement PieChart with Direct Props
Source: https://svelteforge.dashboardpack.com/docs/analytics
Use direct props for PieChart configuration instead of passing a config object. Ensure the innerRadius and legend are set as individual attributes.
```svelte
{#snippet tooltip()}
{/snippet}
```
--------------------------------
### Load content pages with author join in SvelteKit
Source: https://svelteforge.dashboardpack.com/docs/content-management
Uses a Drizzle ORM left join to fetch page data along with the associated author's name for the content table.
```typescript
// content/+page.server.ts — load function with author join
export const load: PageServerLoad = async () => {
const allPages = db
.select({
id: pages.id,
title: pages.title,
slug: pages.slug,
status: pages.status,
template: pages.template,
authorName: users.name,
createdAt: pages.createdAt,
updatedAt: pages.updatedAt,
publishedAt: pages.publishedAt
})
.from(pages)
.leftJoin(users, eq(pages.authorId, users.id))
.orderBy(desc(pages.createdAt))
.all();
return { pages: allPages };
};
```
--------------------------------
### Implement Auth Guard in SvelteKit Layout
Source: https://svelteforge.dashboardpack.com/docs/routing
Protects routes by checking authentication, enforcing maintenance mode, and pre-loading sidebar data for all child routes.
```typescript
// src/routes/(app)/+layout.server.ts
import { redirect, error } from "@sveltejs/kit";
import { db } from "$lib/server/db/index.js";
import { notifications, appSettings } from "$lib/server/db/schema.js";
import { eq, and, or, isNull, sql, desc } from "drizzle-orm";
import type { LayoutServerLoad } from "./$types.js";
export const load: LayoutServerLoad = async ({ locals }) => {
// Auth check — redirect to login if not authenticated
if (!locals.user) {
redirect(302, "/login");
}
// Maintenance mode — block non-admins with 503
const maintenanceSetting = await db.query.appSettings.findFirst({
where: eq(appSettings.key, "maintenanceMode"),
});
if (maintenanceSetting?.value === "true" && locals.user.role !== "admin") {
error(503, "The application is currently under maintenance.");
}
// Load sidebar data: unread count + recent notifications
const userNotificationFilter = or(
eq(notifications.userId, locals.user.id),
isNull(notifications.userId)
);
const [countResult] = await db
.select({ count: sql`count(*)` })
.from(notifications)
.where(and(eq(notifications.read, false), userNotificationFilter));
const recentNotifications = await db
.select({
id: notifications.id,
title: notifications.title,
message: notifications.message,
type: notifications.type,
createdAt: notifications.createdAt,
})
.from(notifications)
.where(and(eq(notifications.read, false), userNotificationFilter))
.orderBy(desc(notifications.createdAt))
.limit(5);
return {
user: locals.user,
unreadNotificationCount: countResult?.count ?? 0,
recentNotifications,
};
};
```
--------------------------------
### Implement Auth Guard in SvelteKit Layout
Source: https://svelteforge.dashboardpack.com/docs/authentication
Protects routes by checking for a user session and enforcing maintenance mode for non-admin users.
```typescript
export const load: LayoutServerLoad = async ({ locals }) => {
if (!locals.user) {
redirect(302, "/login");
}
// Check maintenance mode
const maintenanceSetting = await db.query.appSettings.findFirst({
where: eq(appSettings.key, "maintenanceMode"),
});
if (maintenanceSetting?.value === "true" && locals.user.role !== "admin") {
error(503, "The application is currently under maintenance.");
}
return { user: locals.user, ... };
};
```
--------------------------------
### Define Server-Side Form Action
Source: https://svelteforge.dashboardpack.com/docs/routing
Handles form data extraction and server-side validation within a SvelteKit +page.server.ts file.
```typescript
// src/routes/(app)/users/+page.server.ts
import { fail } from "@sveltejs/kit";
import type { Actions } from "./$types.js";
export const actions: Actions = {
create: async ({ request }) => {
const formData = await request.formData();
const name = formData.get("name");
const email = formData.get("email");
const username = formData.get("username");
const password = formData.get("password");
const role = formData.get("role");
// Server-side validation
if (typeof name !== "string" || name.length < 1 || name.length > 100) {
return fail(400, { message: "Name is required (1-100 characters)" });
}
if (typeof email !== "string" || !email.includes("@")) {
return fail(400, { message: "Valid email is required" });
}
// ... hash password, insert into database
await db.insert(users).values({
id: generateId(10),
email: email.toLowerCase(),
username: username.toLowerCase(),
passwordHash,
name,
role: role as "admin" | "editor" | "viewer",
});
return { success: true };
},
};
```
--------------------------------
### Handling form submission with use:enhance
Source: https://svelteforge.dashboardpack.com/docs/settings
Use the enhance callback to manage toast notifications and update form results asynchronously.
```svelte
```
--------------------------------
### Generate and store password reset token
Source: https://svelteforge.dashboardpack.com/docs/authentication
Creates a 25-character token, hashes it, and stores it in the database with a one-hour expiration.
```javascript
// Generate and store hashed token
const token = generateId(25);
const tokenHash = /* SHA-256 hash of token */;
const expiresAt = new Date(Date.now() + 60 * 60 * 1000); // 1 hour
await db.insert(passwordResetTokens).values({
id: tokenId,
userId: user.id,
tokenHash,
expiresAt,
});
console.log(`[Password Reset] URL: /reset-password?token=${token}`);
```
--------------------------------
### Implement Auth Guard in SvelteKit Layout
Source: https://svelteforge.dashboardpack.com/docs/project-structure
Protects routes within the (app) group by checking for user authentication and maintenance mode status.
```typescript
// src/routes/(app)/+layout.server.ts
export const load: LayoutServerLoad = async ({ locals }) => {
if (!locals.user) {
redirect(302, "/login");
}
// Check maintenance mode
const maintenanceSetting = await db.query.appSettings.findFirst({
where: eq(appSettings.key, "maintenanceMode"),
});
if (maintenanceSetting?.value === "true" && locals.user.role !== "admin") {
error(503, "The application is currently under maintenance.");
}
return { user: locals.user, ... };
};
```
--------------------------------
### Compose Tailwind classes with cn()
Source: https://svelteforge.dashboardpack.com/docs/components
Combines clsx and tailwind-merge to resolve conflicting Tailwind classes and handle conditional styling. Import from $lib/utils for consistent class management.
```typescript
import { cn } from "$lib/utils";
// Merge base classes with conditional and override classes
cn("px-4 py-2 bg-primary", isActive && "bg-primary/90", className);
// tailwind-merge ensures no conflicting classes survive
```
--------------------------------
### Responsive Grid Layout
Source: https://svelteforge.dashboardpack.com/docs/theming
Use these Tailwind grid utilities to create layouts that stack vertically on mobile and expand to multiple columns on larger viewports.
```html
```
--------------------------------
### Create Svelte 5 Page Component
Source: https://svelteforge.dashboardpack.com/docs/routing
Displays the data returned from the server load function using Svelte 5 props.
```html
Reports
{#each data.stats as stat}
{stat.status}
{stat.count}
{/each}
```
--------------------------------
### Unit test SvelteKit load functions
Source: https://svelteforge.dashboardpack.com/docs/testing
Uses a mock event object with locals to test load function behavior and data return shapes.
```typescript
describe("load function", () => {
it("returns user list for admin", async () => {
// Seed the test database
const admin = createTestUser(testDb, { role: "admin" });
createTestUser(testDb, {
email: "viewer@test.com",
username: "viewer",
role: "viewer",
});
// Call the load function
const result = await load({
locals: createMockLocals({ user: admin }),
url: new URL("http://localhost/users"),
}) as any;
// Assert returned data shape
expect(result.users).toHaveLength(2);
expect(result.users[0]).toHaveProperty("id");
expect(result.users[0]).toHaveProperty("email");
expect(result.users[0]).toHaveProperty("role");
// Password hashes should never be returned
expect(result.users[0]).not.toHaveProperty("passwordHash");
});
it("restricts data for non-admin users", async () => {
const viewer = createTestUser(testDb, { role: "viewer" });
const result = await load({
locals: createMockLocals({ user: viewer }),
url: new URL("http://localhost/users"),
}) as any;
// Viewers may see limited data or get redirected
// depending on the page's authorization logic
});
});
```
--------------------------------
### Load users from database
Source: https://svelteforge.dashboardpack.com/docs/user-management
Fetches all users from the Drizzle ORM users table, ordered by creation date.
```typescript
// users/+page.server.ts — load function
export const load: PageServerLoad = async () => {
const allUsers = db.select().from(users).orderBy(desc(users.createdAt)).all();
return { users: allUsers };
};
```