aphex Svelte Themes

Aphex

A modern, extensible headless CMS built with SvelteKit, featuring a portable core package, database/storage agnostic adapters, and a Sanity-inspired admin interface.

AphexCMS Logo

AphexCMS

A Sanity-inspired, database-agnostic CMS built with SvelteKit V2 (Svelte 5)

AphexCMS Responsive Demo

✨ Features

  • 🎨 Sanity-inspired UI - Responsive 3-panel admin interface
  • πŸ”Œ Database Agnostic - PostgreSQL included, MongoDB/SQLite via adapters
  • ☁️ Storage Flexible - Local filesystem or S3-compatible (R2, AWS S3, MinIO)
  • πŸ” Auth Agnostic - Bring your own auth (Better Auth included by default)
  • πŸ“ Type-Safe Schemas - Define content models with full TypeScript support
  • βœ… Real-time Validation - Field-level validation with Sanity-style fluent API
  • πŸ”„ Auto-Save - Never lose work with smart draft management
  • πŸ“¦ Hash-Based Publishing - Sanity-style change detection with future versioning support
  • 🏒 Multi-Tenancy - Built-in organization support with Row-Level Security
  • πŸ”‘ API Keys - Programmatic access with rate limiting
  • πŸš€ GraphQL Plugin - Auto-generated GraphQL API from your schemas
  • πŸ“š Reference Resolution - Nested depth control with circular protection

πŸ“¦ Packages

Package Description
@aphexcms/cms-core Database-agnostic core engine with admin UI, API handlers, and built-in GraphQL
@aphexcms/postgresql-adapter PostgreSQL implementation with Drizzle ORM
@aphexcms/storage-s3 S3-compatible storage (R2, AWS S3, MinIO, etc.)
@aphexcms/nodemailer-adapter Nodemailer/SMTP email adapter (with Mailpit helper for local dev)
@aphexcms/resend-adapter Resend API email adapter for production
@aphexcms/ui Shared shadcn-svelte component library
@aphexcms/base Starter template scaffolded by create-aphex
@aphexcms/studio Reference implementation app (drives the template)
create-aphex Scaffolder invoked by pnpm create aphex / npm create aphex@latest

πŸ’‘ Architecture deep-dive: See ARCHITECTURE.md for detailed design patterns and internals.

πŸ’‘ Adding UI components: Run pnpm shadcn <component-name> to add shadcn-svelte components to @aphexcms/ui

πŸš€ Quick Start

The fastest way to get started:

pnpm create aphex my-app
# or
npm create aphex my-app
# or
npx create-aphex my-app

This will:

  • Prompt you for a project name
  • Scaffold a full Aphex CMS project
  • Generate a .env file with all required environment variables
  • Provide next steps for starting your project

Then:

cd your-project-name
pnpm install
pnpm db:start      # Start PostgreSQL via Docker
pnpm db:push       # Push database schema
pnpm dev           # Start development server

πŸŽ‰ Admin UI: http://localhost:5173/admin

Manual Installation (Development)

If you want to contribute to Aphex or work with the monorepo:

# Clone and install
git clone https://github.com/IcelandicIcecream/aphex.git
cd aphex
pnpm install

# Configure environment
cd apps/studio
cp .env.example .env
# Default values work for local development
cd ../..

# Start database and migrate
pnpm db:start
pnpm db:migrate

# Start dev server
pnpm dev

πŸŽ‰ Admin UI: http://localhost:5173/admin

Storage Configuration (Optional)

By default, uses local filesystem. For cloud storage:

pnpm add @aphexcms/storage-s3
// apps/studio/src/lib/server/storage/index.ts
import { s3Storage } from '@aphexcms/storage-s3';

export const storageAdapter = s3Storage({
    bucket: env.R2_BUCKET,
    endpoint: env.R2_ENDPOINT,
    accessKeyId: env.R2_ACCESS_KEY_ID,
    secretAccessKey: env.R2_SECRET_ACCESS_KEY,
    publicUrl: env.R2_PUBLIC_URL
}).adapter;
// aphex.config.ts
import { storageAdapter } from './src/lib/server/storage';

export default createCMSConfig({
    storage: storageAdapter // Pass your adapter
});

πŸ“– Defining Content Schemas

Content models live in your app as TypeScript objects:

// apps/studio/src/lib/schemaTypes/page.ts
export const page: SchemaType = {
    name: 'page',
    type: 'document',
    title: 'Page',
    fields: [
        {
            name: 'title',
            type: 'string',
            title: 'Title',
            validation: (Rule) => Rule.required().max(100)
        },
        {
            name: 'slug',
            type: 'slug',
            title: 'URL Slug',
            source: 'title', // Auto-generate from title
            validation: (Rule) => Rule.required()
        },
        {
            name: 'content',
            type: 'array',
            title: 'Content Blocks',
            of: [{ type: 'textBlock' }, { type: 'imageBlock' }, { type: 'catalogBlock' }]
        },
        {
            name: 'author',
            type: 'reference',
            title: 'Author',
            to: [{ type: 'author' }] // Reference to other documents
        }
    ]
};

Register schemas in your config:

// aphex.config.ts
import { page, author, textBlock } from './src/lib/schemaTypes';

export default createCMSConfig({
    schemaTypes: [page, author, textBlock]
    // ...
});

Available field types: string, text, number, boolean, slug, url, date, datetime, image, file, array, object, reference

πŸ› οΈ Tech Stack

🎨 Admin Interface

The admin UI is a responsive 3-panel layout inspired by Sanity Studio:

  • Desktop: Side-by-side panels (types β†’ documents β†’ editor)
  • Mobile: Stack navigation with breadcrumbs
  • Real-time validation with inline error messages
  • Auto-save every 2 seconds (never lose work!)
  • Nested reference editing via modal overlays
  • Drag-and-drop array field reordering

πŸ” API Features

Reference Resolution with Depth Control

# Just IDs (default)
GET /api/documents/123

# Resolve first-level references
GET /api/documents/123?depth=1

# Resolve nested references
GET /api/documents/123?depth=2

Circular reference protection prevents infinite loops. Max depth: 5.

GraphQL API

GraphQL is built into cms-core and enabled by default. To customize:

export default createCMSConfig({
    graphql: {
        path: '/api/graphql',
        enableGraphiQL: true
    }
});

Visit /api/graphql for GraphiQL interface with auto-generated schema.

πŸ› οΈ Development Commands

# Development
pnpm dev              # Start all packages in watch mode
pnpm dev:studio       # Start studio app only
pnpm dev:package      # Start cms-core package only
pnpm dev:docs         # Start dev server

# Building
pnpm build            # Build all packages (Turborepo)
pnpm preview          # Preview production build

# Database
pnpm db:start         # Start PostgreSQL (Docker)
pnpm db:push          # Push schema changes (dev)
pnpm db:generate      # Generate migrations
pnpm db:migrate       # Run migrations (prod)
pnpm db:studio        # Open Drizzle Studio

# Code Quality
pnpm lint             # Prettier + ESLint check
pnpm format           # Format code with Prettier
pnpm check            # Type-check all packages

# UI Components (shadcn-svelte β†’ @aphexcms/ui)
pnpm shadcn button    # Add button component
pnpm shadcn dialog    # Add dialog component
# Components shared between cms-core & studio

πŸ” Authentication

Batteries included with Better Auth:

  • βœ… Session-based auth (email/password)
  • βœ… API keys with rate limiting (10k requests/day)
  • βœ… Multi-tenancy with organizations
  • βœ… Row-Level Security (RLS)

API Key Usage

curl http://localhost:5173/api/documents?docType=page \
  -H "x-api-key: your-api-key-here"

Generate keys from /admin/settings.

Bring your own auth: Implement the AuthProvider interface to use Auth.js, Lucia, or custom solutions.

🀝 Contributing

Code Standards

  • βœ… Format before committing: pnpm format
  • βœ… Type-check: pnpm check
  • βœ… Use Svelte 5 runes ($state, $derived, $effect)
  • βœ… Follow Conventional Commits

Adding Features

  • Database Adapters: Implement DatabaseAdapter interface in a new package + AuthProvider
  • Storage Adapters: Implement StorageAdapter interface
  • Field Types: Add Svelte component + TypeScript type
  • Plugins: Implement CMSPlugin interface

See ARCHITECTURE.md for detailed extension guides.

Reporting Issues

Include:

  • OS, Node version, pnpm version
  • Steps to reproduce
  • Expected vs actual behavior
  • Error logs (browser console + terminal)

πŸ“š Documentation

🎯 Roadmap

Shipped

  • CLI scaffolding β€” pnpm create aphex / npm create aphex@latest (published as create-aphex)
  • CI/CD pipeline β€” release.yml + sync-template.yml + Changesets
  • Unified Local/HTTP/GraphQL API β€” one schema, three surfaces, Zod-validated contracts
  • Auto-generated GraphQL β€” queries, mutations, filters, GraphiQL
  • Draft/published workflow β€” hash-based change detection + auto-save
  • Version history β€” rolling per-document versions with configurable maxVersions (GET /api/documents/{id}/versions)
  • Multi-tenancy β€” organizations with parent/child hierarchy + Postgres RLS
  • Email + invitations β€” Better Auth + Resend/Nodemailer adapters, Mailpit in dev
  • Capability-based access control β€” editable built-in roles, custom per-org roles, schema-level and field-level access rules, policy functions
  • API keys β€” rate-limited, per-organization, with either coarse read/write scopes or a fine-grained capabilities allowlist
  • In-memory caching β€” InMemoryCacheAdapter for published reads + API-key lookups
  • Preview config β€” preview: { select: { title, subtitle } } (with dot-paths) on document + object types; rendered in document list, array item rows, and reference picker
  • Singletons β€” schemas marked singleton: true expose a SingletonCollection<T> surface with get/update/getSingletonId and hide Create/Delete in admin
  • Base template β€” full auth/storage/email/cache setup, synced from apps/studio
  • Standalone build β€” pnpm build works without any .env (server modules guarded with building flag); Dockerfile + Procfile ship in the template for Docker / buildpack deploys
  • One-line Vite config β€” aphex() plugin bundles HMR + dayjs alias + SSR/optimizeDeps tuning so consumers don't copy boilerplate
  • Fast schema HMR β€” schema edits hot-swap the engine config without restarting the Vite dev server (~10Γ— faster than restart-on-change)
  • Documentation site β€” docs.getaphex.com with LLM-friendly llms.txt, per-page markdown, and "Copy / Open in ChatGPT / Open in Claude" actions

Near-term (Priority)

  • Polish admin UI β€” fix half-baked implementations (see issues)
  • Template library β€” more starters beyond base (newsletter, marketing site, docs, portfolio)
  • Rich text / block editor β€” TipTap-backed portable-text–style field
  • Plugin ecosystem β€” documented plugin API + first-party plugins (search, image transforms)
  • Image transforms β€” on-the-fly resize / format / crop (see TODO-image-transforms.md)
  • Contributor docs expansion β€” adapter authoring guides, field type authoring guide

Mid-term

  • Content preview system β€” signed draft URLs for previewing unpublished content in frontends
  • Migration tools β€” import/export utilities for content portability between instances
  • Webhook system β€” event-driven integrations on publish / unpublish / delete
  • Scheduled publishing β€” publish-at / unpublish-at timestamps
  • Media library enhancements β€” folders, tags, bulk actions
  • Redis-backed cache adapter β€” drop-in replacement for InMemoryCacheAdapter
  • Advanced field types β€” code editor, color picker, geopoint

Long-term

  • Localization (i18n) support β€” multi-language content with field-level or document-level translation
  • Real-time collaboration β€” multiplayer editing with presence awareness
  • Approval workflows β€” review β†’ approve β†’ publish with role gating
  • Monitoring & observability β€” built-in analytics, slow-query tracking, audit log UI
  • MySQL / SQLite adapters β€” additional first-party DatabaseAdapter implementations

πŸ™ Acknowledgments

Inspired by Sanity.io β€’ Built with SvelteKit, Drizzle ORM, Better Auth, and shadcn-svelte


Questions? Open an issue or start a discussion

Top categories

Loading Svelte Themes