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.
- Host: GitHub
- URL: https://github.com/icelandicicecream/aphex
- Owner: IcelandicIcecream
- License: mit
- Created: 2025-09-24T16:36:39.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2026-05-05T13:05:29.000Z (16 days ago)
- Last Synced: 2026-05-05T15:42:44.419Z (16 days ago)
- Topics: cms-framework, svelte, sveltekit
- Language: TypeScript
- Homepage: https://getaphex.com/
- Size: 22.6 MB
- Stars: 127
- Watchers: 1
- Forks: 2
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
AphexCMS
A Sanity-inspired, database-agnostic CMS built with SvelteKit V2 (Svelte 5)
[](https://opensource.org/licenses/MIT)
[](https://kit.svelte.dev)
[](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)
---