{"id":46421714,"url":"https://github.com/icelandicicecream/aphex","last_synced_at":"2026-05-12T04:01:36.331Z","repository":{"id":317808746,"uuid":"1063450710","full_name":"IcelandicIcecream/aphex","owner":"IcelandicIcecream","description":"A modern, extensible headless CMS built with SvelteKit, featuring a portable core package, database/storage agnostic adapters, and a Sanity-inspired admin interface.","archived":false,"fork":false,"pushed_at":"2026-05-05T13:05:29.000Z","size":23652,"stargazers_count":127,"open_issues_count":8,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-05T15:42:44.419Z","etag":null,"topics":["cms-framework","svelte","sveltekit"],"latest_commit_sha":null,"homepage":"https://getaphex.com/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IcelandicIcecream.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["IcelandicIcecream"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2025-09-24T16:36:39.000Z","updated_at":"2026-05-05T13:05:38.000Z","dependencies_parsed_at":"2025-10-27T08:32:28.664Z","dependency_job_id":null,"html_url":"https://github.com/IcelandicIcecream/aphex","commit_stats":null,"previous_names":["icelandicicecream/aphex"],"tags_count":134,"template":false,"template_full_name":null,"purl":"pkg:github/IcelandicIcecream/aphex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IcelandicIcecream%2Faphex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IcelandicIcecream%2Faphex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IcelandicIcecream%2Faphex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IcelandicIcecream%2Faphex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IcelandicIcecream","download_url":"https://codeload.github.com/IcelandicIcecream/aphex/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IcelandicIcecream%2Faphex/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32922890,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-11T17:09:15.040Z","status":"online","status_checked_at":"2026-05-12T02:00:06.338Z","response_time":102,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cms-framework","svelte","sveltekit"],"created_at":"2026-03-05T16:21:40.122Z","updated_at":"2026-05-12T04:01:36.324Z","avatar_url":"https://github.com/IcelandicIcecream.png","language":"TypeScript","funding_links":["https://github.com/sponsors/IcelandicIcecream"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"./apps/studio/static/images/aphex-darkmode.png\" alt=\"AphexCMS Logo\" width=\"80\" /\u003e\n  \u003cbr\u003e\n  \u003ch1\u003eAphexCMS\u003c/h1\u003e\n  \u003cp\u003e\u003cstrong\u003eA Sanity-inspired, database-agnostic CMS built with SvelteKit V2 (Svelte 5)\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"./responsive-demo.gif\" alt=\"AphexCMS Responsive Demo\" width=\"100%\" /\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![SvelteKit](https://img.shields.io/badge/SvelteKit-V2-FF3E00?logo=svelte)](https://kit.svelte.dev)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.0-3178C6?logo=typescript)](https://www.typescriptlang.org/)\n\n\u003c/div\u003e\n\n## ✨ Features\n\n- 🎨 **Sanity-inspired UI** - Responsive 3-panel admin interface\n- 🔌 **Database Agnostic** - PostgreSQL included, MongoDB/SQLite via adapters\n- ☁️ **Storage Flexible** - Local filesystem or S3-compatible (R2, AWS S3, MinIO)\n- 🔐 **Auth Agnostic** - Bring your own auth (Better Auth included by default)\n- 📝 **Type-Safe Schemas** - Define content models with full TypeScript support\n- ✅ **Real-time Validation** - Field-level validation with Sanity-style fluent API\n- 🔄 **Auto-Save** - Never lose work with smart draft management\n- 📦 **Hash-Based Publishing** - Sanity-style change detection with future versioning support\n- 🏢 **Multi-Tenancy** - Built-in organization support with Row-Level Security\n- 🔑 **API Keys** - Programmatic access with rate limiting\n- 🚀 **GraphQL Plugin** - Auto-generated GraphQL API from your schemas\n- 📚 **Reference Resolution** - Nested depth control with circular protection\n\n## 📦 Packages\n\n| Package                        | Description                                                                     |\n| ------------------------------ | ------------------------------------------------------------------------------- |\n| `@aphexcms/cms-core`           | Database-agnostic core engine with admin UI, API handlers, and built-in GraphQL |\n| `@aphexcms/postgresql-adapter` | PostgreSQL implementation with Drizzle ORM                                      |\n| `@aphexcms/storage-s3`         | S3-compatible storage (R2, AWS S3, MinIO, etc.)                                 |\n| `@aphexcms/nodemailer-adapter` | Nodemailer/SMTP email adapter (with Mailpit helper for local dev)               |\n| `@aphexcms/resend-adapter`     | Resend API email adapter for production                                         |\n| `@aphexcms/ui`                 | Shared [shadcn-svelte](https://shadcn-svelte.com) component library             |\n| `@aphexcms/base`               | Starter template scaffolded by `create-aphex`                                   |\n| `@aphexcms/studio`             | Reference implementation app (drives the template)                              |\n| `create-aphex`                 | Scaffolder invoked by `pnpm create aphex` / `npm create aphex@latest`           |\n\n\u003e 💡 **Architecture deep-dive**: See [ARCHITECTURE.md](./ARCHITECTURE.md) for detailed design patterns and internals.\n\u003e\n\u003e 💡 **Adding UI components**: Run `pnpm shadcn \u003ccomponent-name\u003e` to add shadcn-svelte components to `@aphexcms/ui`\n\n## 🚀 Quick Start\n\n### Using `create-aphex` (Recommended)\n\nThe fastest way to get started:\n\n```bash\npnpm create aphex my-app\n# or\nnpm create aphex my-app\n# or\nnpx create-aphex my-app\n```\n\nThis will:\n\n- Prompt you for a project name\n- Scaffold a full Aphex CMS project\n- Generate a `.env` file with all required environment variables\n- Provide next steps for starting your project\n\nThen:\n\n```bash\ncd your-project-name\npnpm install\npnpm db:start      # Start PostgreSQL via Docker\npnpm db:push       # Push database schema\npnpm dev           # Start development server\n```\n\n🎉 **Admin UI**: http://localhost:5173/admin\n\n### Manual Installation (Development)\n\nIf you want to contribute to Aphex or work with the monorepo:\n\n```bash\n# Clone and install\ngit clone https://github.com/IcelandicIcecream/aphex.git\ncd aphex\npnpm install\n\n# Configure environment\ncd apps/studio\ncp .env.example .env\n# Default values work for local development\ncd ../..\n\n# Start database and migrate\npnpm db:start\npnpm db:migrate\n\n# Start dev server\npnpm dev\n```\n\n🎉 **Admin UI**: http://localhost:5173/admin\n\n### Storage Configuration (Optional)\n\nBy default, uses **local filesystem**. For cloud storage:\n\n```bash\npnpm add @aphexcms/storage-s3\n```\n\n```typescript\n// apps/studio/src/lib/server/storage/index.ts\nimport { s3Storage } from '@aphexcms/storage-s3';\n\nexport const storageAdapter = s3Storage({\n\tbucket: env.R2_BUCKET,\n\tendpoint: env.R2_ENDPOINT,\n\taccessKeyId: env.R2_ACCESS_KEY_ID,\n\tsecretAccessKey: env.R2_SECRET_ACCESS_KEY,\n\tpublicUrl: env.R2_PUBLIC_URL\n}).adapter;\n```\n\n```typescript\n// aphex.config.ts\nimport { storageAdapter } from './src/lib/server/storage';\n\nexport default createCMSConfig({\n\tstorage: storageAdapter // Pass your adapter\n});\n```\n\n## 📖 Defining Content Schemas\n\nContent models live in **your app** as TypeScript objects:\n\n```typescript\n// apps/studio/src/lib/schemaTypes/page.ts\nexport const page: SchemaType = {\n\tname: 'page',\n\ttype: 'document',\n\ttitle: 'Page',\n\tfields: [\n\t\t{\n\t\t\tname: 'title',\n\t\t\ttype: 'string',\n\t\t\ttitle: 'Title',\n\t\t\tvalidation: (Rule) =\u003e Rule.required().max(100)\n\t\t},\n\t\t{\n\t\t\tname: 'slug',\n\t\t\ttype: 'slug',\n\t\t\ttitle: 'URL Slug',\n\t\t\tsource: 'title', // Auto-generate from title\n\t\t\tvalidation: (Rule) =\u003e Rule.required()\n\t\t},\n\t\t{\n\t\t\tname: 'content',\n\t\t\ttype: 'array',\n\t\t\ttitle: 'Content Blocks',\n\t\t\tof: [{ type: 'textBlock' }, { type: 'imageBlock' }, { type: 'catalogBlock' }]\n\t\t},\n\t\t{\n\t\t\tname: 'author',\n\t\t\ttype: 'reference',\n\t\t\ttitle: 'Author',\n\t\t\tto: [{ type: 'author' }] // Reference to other documents\n\t\t}\n\t]\n};\n```\n\nRegister schemas in your config:\n\n```typescript\n// aphex.config.ts\nimport { page, author, textBlock } from './src/lib/schemaTypes';\n\nexport default createCMSConfig({\n\tschemaTypes: [page, author, textBlock]\n\t// ...\n});\n```\n\n**Available field types**: `string`, `text`, `number`, `boolean`, `slug`, `url`, `date`, `datetime`, `image`, `file`, `array`, `object`, `reference`\n\n## 🛠️ Tech Stack\n\n- **[SvelteKit V2](https://kit.svelte.dev)** - Framework with Svelte 5 runes\n- **[Drizzle ORM](https://orm.drizzle.team)** - Type-safe database queries\n- **[Better Auth](https://better-auth.com)** - Authentication \u0026 sessions\n- **[Turborepo](https://turbo.build)** - Monorepo build system\n- **[Tailwind CSS v4](https://tailwindcss.com)** - Styling\n- **[shadcn-svelte](https://shadcn-svelte.com)** - UI components\n\n## 🎨 Admin Interface\n\nThe admin UI is a **responsive 3-panel layout** inspired by Sanity Studio:\n\n- **Desktop**: Side-by-side panels (types → documents → editor)\n- **Mobile**: Stack navigation with breadcrumbs\n- **Real-time validation** with inline error messages\n- **Auto-save** every 2 seconds (never lose work!)\n- **Nested reference editing** via modal overlays\n- **Drag-and-drop** array field reordering\n\n## 🔍 API Features\n\n### Reference Resolution with Depth Control\n\n```bash\n# Just IDs (default)\nGET /api/documents/123\n\n# Resolve first-level references\nGET /api/documents/123?depth=1\n\n# Resolve nested references\nGET /api/documents/123?depth=2\n```\n\n**Circular reference protection** prevents infinite loops. Max depth: 5.\n\n### GraphQL API\n\nGraphQL is built into `cms-core` and enabled by default. To customize:\n\n```typescript\nexport default createCMSConfig({\n\tgraphql: {\n\t\tpath: '/api/graphql',\n\t\tenableGraphiQL: true\n\t}\n});\n```\n\nVisit `/api/graphql` for GraphiQL interface with auto-generated schema.\n\n## 🛠️ Development Commands\n\n```bash\n# Development\npnpm dev              # Start all packages in watch mode\npnpm dev:studio       # Start studio app only\npnpm dev:package      # Start cms-core package only\npnpm dev:docs         # Start dev server\n\n# Building\npnpm build            # Build all packages (Turborepo)\npnpm preview          # Preview production build\n\n# Database\npnpm db:start         # Start PostgreSQL (Docker)\npnpm db:push          # Push schema changes (dev)\npnpm db:generate      # Generate migrations\npnpm db:migrate       # Run migrations (prod)\npnpm db:studio        # Open Drizzle Studio\n\n# Code Quality\npnpm lint             # Prettier + ESLint check\npnpm format           # Format code with Prettier\npnpm check            # Type-check all packages\n\n# UI Components (shadcn-svelte → @aphexcms/ui)\npnpm shadcn button    # Add button component\npnpm shadcn dialog    # Add dialog component\n# Components shared between cms-core \u0026 studio\n```\n\n## 🔐 Authentication\n\n**Batteries included** with [Better Auth](https://better-auth.com):\n\n- ✅ Session-based auth (email/password)\n- ✅ API keys with rate limiting (10k requests/day)\n- ✅ Multi-tenancy with organizations\n- ✅ Row-Level Security (RLS)\n\n### API Key Usage\n\n```bash\ncurl http://localhost:5173/api/documents?docType=page \\\n  -H \"x-api-key: your-api-key-here\"\n```\n\nGenerate keys from `/admin/settings`.\n\n\u003e **Bring your own auth**: Implement the `AuthProvider` interface to use Auth.js, Lucia, or custom solutions.\n\n## 🤝 Contributing\n\n### Code Standards\n\n- ✅ Format before committing: `pnpm format`\n- ✅ Type-check: `pnpm check`\n- ✅ Use Svelte 5 runes (`$state`, `$derived`, `$effect`)\n- ✅ Follow [Conventional Commits](https://www.conventionalcommits.org/)\n\n### Adding Features\n\n- **Database Adapters**: Implement `DatabaseAdapter` interface in a new package + AuthProvider\n- **Storage Adapters**: Implement `StorageAdapter` interface\n- **Field Types**: Add Svelte component + TypeScript type\n- **Plugins**: Implement `CMSPlugin` interface\n\nSee [ARCHITECTURE.md](./ARCHITECTURE.md) for detailed extension guides.\n\n### Reporting Issues\n\nInclude:\n\n- OS, Node version, pnpm version\n- Steps to reproduce\n- Expected vs actual behavior\n- Error logs (browser console + terminal)\n\n## 📚 Documentation\n\n- **[ARCHITECTURE.md](./ARCHITECTURE.md)** - Deep dive into design patterns and internals\n- **[CONTRIBUTING.md](./CONTRIBUTING.md)** - Development guidelines and PR process\n\n## 🎯 Roadmap\n\n### Shipped\n\n- [x] **CLI scaffolding** — `pnpm create aphex` / `npm create aphex@latest` (published as [`create-aphex`](https://www.npmjs.com/package/create-aphex))\n- [x] **CI/CD pipeline** — `release.yml` + `sync-template.yml` + Changesets\n- [x] **Unified Local/HTTP/GraphQL API** — one schema, three surfaces, Zod-validated contracts\n- [x] **Auto-generated GraphQL** — queries, mutations, filters, GraphiQL\n- [x] **Draft/published workflow** — hash-based change detection + auto-save\n- [x] **Version history** — rolling per-document versions with configurable `maxVersions` (`GET /api/documents/{id}/versions`)\n- [x] **Multi-tenancy** — organizations with parent/child hierarchy + Postgres RLS\n- [x] **Email + invitations** — Better Auth + Resend/Nodemailer adapters, Mailpit in dev\n- [x] **Capability-based access control** — editable built-in roles, custom per-org roles, schema-level and field-level access rules, policy functions\n- [x] **API keys** — rate-limited, per-organization, with either coarse `read`/`write` scopes or a fine-grained `capabilities` allowlist\n- [x] **In-memory caching** — `InMemoryCacheAdapter` for `published` reads + API-key lookups\n- [x] **Preview config** — `preview: { select: { title, subtitle } }` (with dot-paths) on document + object types; rendered in document list, array item rows, and reference picker\n- [x] **Singletons** — schemas marked `singleton: true` expose a `SingletonCollection\u003cT\u003e` surface with `get`/`update`/`getSingletonId` and hide Create/Delete in admin\n- [x] **Base template** — full auth/storage/email/cache setup, synced from `apps/studio`\n- [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\n- [x] **One-line Vite config** — `aphex()` plugin bundles HMR + dayjs alias + SSR/optimizeDeps tuning so consumers don't copy boilerplate\n- [x] **Fast schema HMR** — schema edits hot-swap the engine config without restarting the Vite dev server (~10× faster than restart-on-change)\n- [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\n\n### Near-term (Priority)\n\n- [ ] **Polish admin UI** — fix half-baked implementations (see [issues](https://github.com/IcelandicIcecream/aphex/issues))\n- [ ] **Template library** — more starters beyond `base` (newsletter, marketing site, docs, portfolio)\n- [ ] **Rich text / block editor** — TipTap-backed `portable-text`–style field\n- [ ] **Plugin ecosystem** — documented plugin API + first-party plugins (search, image transforms)\n- [ ] **Image transforms** — on-the-fly resize / format / crop (see [`TODO-image-transforms.md`](./TODO-image-transforms.md))\n- [ ] **Contributor docs expansion** — adapter authoring guides, field type authoring guide\n\n### Mid-term\n\n- [ ] **Content preview system** — signed draft URLs for previewing unpublished content in frontends\n- [ ] **Migration tools** — import/export utilities for content portability between instances\n- [ ] **Webhook system** — event-driven integrations on publish / unpublish / delete\n- [ ] **Scheduled publishing** — publish-at / unpublish-at timestamps\n- [ ] **Media library enhancements** — folders, tags, bulk actions\n- [ ] **Redis-backed cache adapter** — drop-in replacement for `InMemoryCacheAdapter`\n- [ ] **Advanced field types** — code editor, color picker, geopoint\n\n### Long-term\n\n- [ ] **Localization (i18n) support** — multi-language content with field-level or document-level translation\n- [ ] **Real-time collaboration** — multiplayer editing with presence awareness\n- [ ] **Approval workflows** — review → approve → publish with role gating\n- [ ] **Monitoring \u0026 observability** — built-in analytics, slow-query tracking, audit log UI\n- [ ] **MySQL / SQLite adapters** — additional first-party `DatabaseAdapter` implementations\n\n## 🙏 Acknowledgments\n\nInspired 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)\n\n---\n\n\u003cdiv align=\"center\"\u003e\n  \u003cstrong\u003eQuestions?\u003c/strong\u003e Open an \u003ca href=\"https://github.com/IcelandicIcecream/aphex/issues\"\u003eissue\u003c/a\u003e or start a \u003ca href=\"https://github.com/IcelandicIcecream/aphex/discussions\"\u003ediscussion\u003c/a\u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficelandicicecream%2Faphex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ficelandicicecream%2Faphex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficelandicicecream%2Faphex/lists"}