An open API service indexing awesome lists of open source software.

https://github.com/icelandicicecream/aphex

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

cms-framework svelte sveltekit

Last synced: 9 days ago
JSON representation

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

Awesome Lists containing this project

README

          


AphexCMS Logo


AphexCMS


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



AphexCMS Responsive Demo

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![SvelteKit](https://img.shields.io/badge/SvelteKit-V2-FF3E00?logo=svelte)](https://kit.svelte.dev)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.0-3178C6?logo=typescript)](https://www.typescriptlang.org/)

## ✨ 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](https://shadcn-svelte.com) 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](./ARCHITECTURE.md) for detailed design patterns and internals.
>
> πŸ’‘ **Adding UI components**: Run `pnpm shadcn ` to add shadcn-svelte components to `@aphexcms/ui`

## πŸš€ Quick Start

### Using `create-aphex` (Recommended)

The fastest way to get started:

```bash
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:

```bash
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:

```bash
# 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:

```bash
pnpm add @aphexcms/storage-s3
```

```typescript
// 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;
```

```typescript
// 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:

```typescript
// 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:

```typescript
// 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

- **[SvelteKit V2](https://kit.svelte.dev)** - Framework with Svelte 5 runes
- **[Drizzle ORM](https://orm.drizzle.team)** - Type-safe database queries
- **[Better Auth](https://better-auth.com)** - Authentication & sessions
- **[Turborepo](https://turbo.build)** - Monorepo build system
- **[Tailwind CSS v4](https://tailwindcss.com)** - Styling
- **[shadcn-svelte](https://shadcn-svelte.com)** - UI components

## 🎨 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

```bash
# 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:

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

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

## πŸ› οΈ Development Commands

```bash
# 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](https://better-auth.com):

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

### API Key Usage

```bash
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](https://www.conventionalcommits.org/)

### 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](./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

- **[ARCHITECTURE.md](./ARCHITECTURE.md)** - Deep dive into design patterns and internals
- **[CONTRIBUTING.md](./CONTRIBUTING.md)** - Development guidelines and PR process

## 🎯 Roadmap

### Shipped

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

---


Questions? Open an issue or start a discussion