qiick / externa-core
Externa — headless CMS / content API with operator admin UI.
Package info
github.com/qiick-io/externa-core
Language:TypeScript
Type:project
pkg:composer/qiick/externa-core
Requires
- php: ^8.4
- inertiajs/inertia-laravel: ^2.0
- laravel/ai: ^0.7.2
- laravel/fortify: ^1.34
- laravel/framework: ^13.0
- laravel/horizon: ^5.48
- laravel/pulse: ^1.7
- laravel/reverb: ^1.11
- laravel/tinker: ^3.0
- laravel/wayfinder: ^0.1.14
- league/flysystem-aws-s3-v3: ^3.25
- nuwave/lighthouse: ^6.69
- phpoffice/phpspreadsheet: ^5.9
- smalot/pdfparser: ^2.12
- spatie/eloquent-sortable: ^5.0
- spatie/laravel-activitylog: ^5.0
- spatie/laravel-permission: ^7.2
- spatie/laravel-tags: ^4.12
- spatie/laravel-translatable: ^6.13
- symfony/html-sanitizer: ^8.1
Requires (Dev)
- fakerphp/faker: ^1.24
- laravel/boost: ^2.0
- laravel/pail: ^1.2.5
- laravel/pint: ^1.27
- laravel/sail: ^1.53
- mockery/mockery: ^1.6
- nunomaduro/collision: ^8.9
- pestphp/pest: ^4.4
- pestphp/pest-plugin-browser: ^4.0
- pestphp/pest-plugin-laravel: ^4.1
Suggests
- ext-redis: Required for QUEUE_CONNECTION=redis, Horizon, Reverb scaling, and Pulse redis ingest.
- laravel/horizon: Redis queue dashboard and workers (composer require already includes it for full stack).
- laravel/pulse: Application metrics; use redis ingest + pulse:work in production.
- laravel/reverb: WebSocket server for Echo notifications and presence.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-16 19:39:08 UTC
README
Version: 1.0.0-beta.3 (from composer.json; mirrored in package.json). See CHANGELOG.md and Releasing docs.
Externa is a Laravel-native headless CMS: operators manage structured content in a full admin UI; websites and apps consume it through the Public CMS API (/api/v1) and GraphQL (/api/graphql). Optional in-app AI tools respect the signed-in user’s permissions — you own the code, so automation is Jobs/listeners, not a locked Flow canvas.
Who it is for: teams that want a self-hosted content API with a serious admin (collections, files, RBAC) on a stack they already know — Laravel 13, Inertia + React 19, Vite.
| Docs | docs.externa.qiick.io |
| Install | composer create-project qiick/externa-core · Installation · Upgrade · Minimal vs full stack |
| API | Public CMS API · GraphQL · 1.x compatibility |
| Security | SECURITY.md · Threat model |
| Issues | GitHub Issues |
Highlights
- Dynamic collections — fields, locales, lean draft/publish, typed item editor
- Hierarchical files — folders, uploads, versions, async zip
- RBAC + groups — Spatie roles/permissions with group inheritance;
publicrole for the API - Public CMS API + GraphQL — collection access matrix, API keys, origin allowlist; 1.x compatibility policy
- Chat + activity — item/private threads; Spatie activity log
- Optional AI assistant — OpenAI-compatible / LM Studio; tools gated by effective permissions
Stack: Laravel 13, Inertia + React 19, Vite, Spatie Permission / Activitylog, Wayfinder typed routes.
Product UI
Light-theme shots from the admin (demo seed data). More in the docs.
Collection items — list, filters, and actions
Item editor — localized fields and rich text
File manager — folders and assets
Roles — project access control
Chat — collection and private threads
Users — roles, groups, and status
Requirements
| Requirement | Notes |
|---|---|
| PHP 8.4+ | Pinned in .php-version / composer.json (^8.4). Herd PHP 8.4 recommended on macOS. |
| Composer 2 | PHP dependencies and composer setup / composer run dev. |
| Node.js 24 | Pinned in .nvmrc and package.json engines. Use nvm use (or equivalent). |
| Database | SQLite 3.x (local/CI default); PostgreSQL 14+ (16 preferred, production recommended); MySQL 8.0+; MariaDB 10.6+ (10.11+ preferred). MySQL/MariaDB: utf8mb4 / utf8mb4_unicode_ci. Matrix: Supported databases. |
| Redis (optional) | Needed for Horizon, Reverb-friendly realtime, and Pulse redis ingest. Prod without Redis: docs. |
Optional: Laravel Herd (PHP, nginx, .test hosts; Pro adds shared Reverb on :8080). Optional AI: an OpenAI-compatible gateway (e.g. LM Studio) at LOCAL_AI_URL.
Quick start
Operators (recommended): create a new site from Packagist (no git clone):
composer create-project qiick/externa-core:^1.0.0@beta my-externa cd my-externa nvm use # Node 24 composer setup php artisan db:seed php artisan storage:link
Beta tags need Composer stability: @beta (or "minimum-stability": "beta" in a root that requires the package). After Packagist lists a tag, create-project pulls that release; until then use the git contributor path or a VCS repository. Docs: Installation · Packagist & create-project.
Shortcut: composer setup runs install → copy .env if missing → key:generate → migrate → npm install → npm run build. Still run db:seed, storage:link, and Wayfinder (or let Vite generate routes on first npm run dev). Interactive first-run: php artisan externa:install when available (#4).
Contributors (git clone)
git clone https://github.com/qiick-io/externa-core.git cd externa-core nvm use # Node 24 cp .env.example .env # Edit .env: set APP_URL to match how you browse. For no Redis, see “Minimal vs full” below. touch database/database.sqlite # if missing (SQLite default) composer install php artisan key:generate php artisan migrate php artisan db:seed php artisan storage:link npm install php artisan wayfinder:generate --with-form --no-interaction npm run build # or skip and rely on `npm run dev` / Vite HMR
Run locally
Minimal (no Redis — set QUEUE_CONNECTION=database and BROADCAST_CONNECTION=log in .env):
composer run dev
# serve + queue:listen + pail + vite
Or with Herd serving the site: keep Vite + a queue worker (php artisan queue:listen --tries=1 --timeout=0). For Herd HTTPS (herd secure), set HERD_SITE to your hostname (e.g. my-app.test) so Vite can detect TLS certs.
Full stack (Redis + realtime + Pulse — matches .env.example defaults):
- Enable Redis (and Herd Pro Reverb on
:8080if available). - Keep
QUEUE_CONNECTION=redis,BROADCAST_CONNECTION=reverb, and Reverb/Pulse keys from.env.example. - Start workers (Herd Reverb is already up — do not also
reverb:starton the same port):
php artisan horizon php artisan pulse:work npm run dev
Standalone all-in-one (starts its own Reverb — conflicts if Herd already binds :8080):
composer run dev:full
Open APP_URL (your Herd host, http://localhost, or php artisan serve). Unauthenticated / redirects to login.
Dev Container (VS Code / Codespaces)
Open the repo in VS Code Reopen in Container or GitHub Codespaces — .devcontainer/devcontainer.json reuses compose.yaml (app service). Post-create runs composer/npm/migrate/seed. Docs: Installation.
Docker (local full stack)
Official local path is Compose (compose.yaml) — Sail stays in require-dev but is not required. Stack: app (nginx+php-fpm) + Vite + Postgres + Redis + Horizon + Reverb + scheduler + Pulse + Mailpit. Optional MinIO profile for FILES_DISK=s3.
cp .env.docker.example .env docker compose up --build # App: http://localhost:8000 (COMPOSE_APP_URL overrides Herd APP_URL inside containers) # Reverb published on host :8081 (avoids Herd Reverb on :8080) # MinIO: docker compose --profile minio up --build # MySQL: docker compose --profile mysql -f compose.yaml -f compose.mysql.yaml up --build # MariaDB (host :3307): docker compose --profile mariadb -f compose.yaml -f compose.mariadb.yaml up --build
Production: multi-stage Dockerfile (--target production), compose.prod.yaml, .env.docker.prod.example. Probes: GET /health/live, GET /health/ready (+ Laravel /up). Docs: Installation · Deployment · Reverse proxy.
First login (local / dev only)
php artisan db:seed creates permissions, roles (super-admin, admin, reader, public), and a super admin from config/super_admin.php:
| Default | |
|---|---|
superadmin@example.com |
|
| Password | password |
Override with INITIAL_SUPER_ADMIN_* in .env before seeding. Local/dev only — change or remove before any shared or production deploy.
Important environment variables
Copy from .env.example and tune. Full reference: Environment variables.
| Group | Keys (curated) | Notes |
|---|---|---|
| App | APP_NAME, APP_ENV, APP_KEY, APP_DEBUG, APP_URL |
APP_URL must match how you browse. HTTP is fine for password login, TOTP 2FA, and the rest of the CMS. Passkeys / WebAuthn need a secure context: HTTPS, or http://localhost / http://*.localhost. Plain http://*.test hosts are not secure — browsers hide PublicKeyCredential. Local HTTPS: herd secure <site>, matching APP_URL=https://…, and HERD_SITE=<site> for Vite TLS detection. After switching back to HTTP (herd unsecure), clear http + https cookies for the site or browsers may keep Secure session cookies → 419 Page Expired on login. Docs: Passkeys. |
| Database | DB_CONNECTION (+ DB_* if not SQLite) |
Default sqlite. Also pgsql, mysql, mariadb — see Supported databases. |
| Session / cache | SESSION_DRIVER, CACHE_STORE |
Default database. |
| Queue | QUEUE_CONNECTION |
Full: redis + Horizon. Minimal: database + queue:listen. |
| Redis | REDIS_CLIENT, REDIS_HOST, REDIS_PORT, REDIS_PASSWORD |
Required for Horizon / Pulse redis ingest. |
| Broadcast / Reverb | BROADCAST_CONNECTION, REVERB_*, VITE_REVERB_* |
Full: reverb. Minimal: log (60s notification poll). Restart Vite after VITE_REVERB_* changes. |
| Pulse | PULSE_ENABLED, PULSE_INGEST_DRIVER, PULSE_* |
Prefer redis ingest + pulse:work. Disable with PULSE_ENABLED=false when not using Redis. |
| AI | AI_DEFAULT_PROVIDER, LOCAL_AI_URL, LOCAL_AI_MODEL, … |
Optional; defaults target a local OpenAI-compatible gateway. |
| Files | FILES_DISK, FILES_DUPLICATE_SYNC_MAX_BYTES, FILES_ZIP_*, AWS_* |
File manager disk (assets or s3). Async zip / large duplicate need a queue worker. Zip archives stay on the shared local storage volume. |
See .env.example for every key and inline comments.
Optional services
| Service | When you need it |
|---|---|
| Horizon | Redis queues, dashboard Health Horizon cards, /horizon (super-admin). |
| Reverb + Echo | Live admin notifications, presence / avatar connection indicator. Prefer Herd Pro Reverb locally. |
| Pulse | Metrics for dashboard Health; full UI at /pulse. Needs ingest worker when using redis ingest. |
| Queue worker | Always needed for zip downloads, large/bulk duplicates, and collection imports — even on the minimal stack. |
Details: Redis · Horizon · Reverb · Pulse · Operations.
Tests and quality
Use Node 24 for frontend checks (nvm use).
composer test # config:clear + Pint --test + Pest php artisan test # Pest only composer lint # Pint (fix) composer lint:check # Pint --test composer ci:check # npm lint/format/types + composer test npm run lint:check npm run format:check npm run types:check
Pest browser tests live under tests/Browser/. See Testing.
Related projects
| Project | Role |
|---|---|
| Documentation | Product & ops docs |
| externa-bruno | Runnable Public CMS API + GraphQL requests |
| GitHub — externa-core | This repository |
License
MIT — see LICENSE.