Getting started
Quick Start
Get externa-core running on Laravel Herd in a few minutes. For troubleshooting, AI gateway setup, and SSR, use the full Installation guide.
Prerequisites
| Requirement | Notes |
|---|---|
| PHP 8.4 | Pinned in .php-version / composer.json (^8.4). Use Herd’s PHP 8.4 CLI. |
| Composer 2 | PHP dependencies and composer setup / composer run dev. |
| Node.js 24 | Pinned in .nvmrc and package.json engines. Run nvm use (or equivalent). |
| Laravel Herd | Serves the site at a .test host (e.g. http://externa-core.test). |
| Postgres (this example) | Or switch to SQLite — see the commented block in the .env below. |
| Redis (optional) | Needed for Horizon, Reverb-friendly realtime, and Pulse redis ingest. Enable in Herd. |
Optional: Herd Pro Reverb on :8080 for live admin notifications.
1. Clone and enter
git clone <your-fork-or-remote> externa-core
cd externa-core
nvm use # Node 24
Park or link the folder in Herd so http://externa-core.test resolves (or set APP_URL to your Herd host). HTTP is enough for password / TOTP / CMS; passkeys on a .test host need herd secure + https://… — Passkeys.
2. Environment
Either copy the example and edit:
cp .env.example .env
Or paste the Herd-oriented block below into .env (safe local defaults — no production secrets).
Create the Postgres database externa_core in Herd (or your local Postgres) before migrate. For zero-config SQLite instead, use the commented DB_* lines and touch database/database.sqlite.
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
# HTTP OK for password/TOTP/CMS. Passkeys need HTTPS (or localhost) — see /docs/passkeys
APP_URL=http://externa-core.test
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
# Postgres (typical Herd local DB). For SQLite instead:
# DB_CONNECTION=sqlite
# (and: touch database/database.sqlite)
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=externa_core
DB_USERNAME=root
DB_PASSWORD=
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
FILESYSTEM_DISK=local
CACHE_STORE=database
MEMCACHED_HOST=127.0.0.1
# Redis — enable in Herd. Without Redis: QUEUE_CONNECTION=database, BROADCAST_CONNECTION=log
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
QUEUE_CONNECTION=redis
# QUEUE_CONNECTION=database
BROADCAST_CONNECTION=reverb
# BROADCAST_CONNECTION=log
# Herd Pro Reverb defaults (Services → Reverb). Host must be 127.0.0.1 / localhost for Echo.
REVERB_APP_ID=1001
REVERB_APP_KEY=laravel-herd
REVERB_APP_SECRET=secret
REVERB_HOST=127.0.0.1
REVERB_PORT=8080
REVERB_SCHEME=http
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
PULSE_ENABLED=true
PULSE_INGEST_DRIVER=redis
PULSE_REDIS_CONNECTION=pulse
PULSE_STORAGE_KEEP="2 days"
PULSE_INGEST_KEEP="2 days"
MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
FILES_DUPLICATE_SYNC_MAX_BYTES=52428800
FILES_ZIP_TTL_MINUTES=60
FILES_ZIP_MAX_BYTES=104857600
AI_DEFAULT_PROVIDER=local
LOCAL_AI_URL=http://127.0.0.1:1234/v1
LOCAL_AI_API_KEY=
LOCAL_AI_MODEL=openai/gpt-oss-20b
AI_REMOTE_IMPORT_HOSTS=
AI_WEBHOOK_TOKEN=
AI_DAILY_PROMPT_LIMIT=0
AI_EMBEDDINGS_ENABLED=false
AI_MCP_ENABLED=false
Full key reference: Environment variables. Minimal vs Redis/Reverb/Pulse: Minimal vs full stack.
3. Install, migrate, seed
composer install
php artisan key:generate
php artisan migrate --seed
php artisan storage:link
php artisan wayfinder:generate --with-form --no-interaction
npm ci # or: npm install
npm run build # or skip and use `npm run dev` / Vite HMR below
Shortcut: composer setup runs install → copy .env if missing → key:generate → migrate → npm install → npm run build. It does not seed, link storage, or generate Wayfinder — still run those (or let Vite generate routes on first npm run dev).
What seeding creates
php artisan migrate --seed (or db:seed) runs DatabaseSeeder:
PermissionSeeder— syncs Spatie permissions fromPermissionEnumviaphp artisan permissions:syncRoleSeeder— roles:Role Notes super-adminEvery Spatie permission adminEvery Spatie permission readerOnly can-show-*permissionspublicSystem role ( is_system, not assignable); no Spatie admin permissions — used for anonymous Public CMS API; grant collection/file access in the role UICreateSuperAdminSeeder— first user fromconfig/super_admin.php
| Default (local only) | |
|---|---|
superadmin@example.com | |
| Password | password |
Override before seeding:
INITIAL_SUPER_ADMIN_FIRST_NAME=Super
INITIAL_SUPER_ADMIN_LAST_NAME=Admin
INITIAL_SUPER_ADMIN_EMAIL=superadmin@example.com
INITIAL_SUPER_ADMIN_PASSWORD=password
Local / dev only
Change or remove default credentials before any shared or production deploy. Do not commit real secrets.
After upgrades, re-sync permission definitions:
php artisan permissions:sync
# optional: php artisan permissions:sync --prune
More on the public role matrix: Roles & permissions · Public CMS API.
4. Run
Herd already serves HTTP at APP_URL. You still need Vite and a queue path.
Minimal (no Redis — set QUEUE_CONNECTION=database and BROADCAST_CONNECTION=log):
composer run dev
# serve + queue:listen + pail + vite
With Herd serving the site you can skip artisan serve and run Vite + a worker yourself (npm run dev and php artisan queue:listen --tries=1 --timeout=0).
Full stack (matches the .env above — Redis + Herd Reverb + Pulse):
php artisan horizon
php artisan pulse:work
npm run dev
Do not also run php artisan reverb:start if Herd Pro already binds :8080.
Standalone all-in-one (starts its own Reverb — conflicts with Herd Reverb on the same port):
composer run dev:full
Open http://externa-core.test (or your APP_URL). Unauthenticated / redirects to login — use the seeded super admin.
Optional services
| Need | One-liner | Docs |
|---|---|---|
| Redis | Enable in Herd; keep REDIS_* as above | Redis |
| Horizon | php artisan horizon | Horizon |
| Reverb + Echo | Herd Pro on :8080 + REVERB_* / VITE_REVERB_* | Reverb & Echo |
| Pulse | php artisan pulse:work (redis ingest) | Pulse & Health |
| Queues / scheduler | Ops overview | Operations |
Related packages
| Repo | Role |
|---|---|
| externa-core | Laravel + Inertia app (this Quick Start) |
| externa-docs | Product docs (this site) |
| externa-bruno | Runnable Bruno collection for Public CMS API (/api/v1) + GraphQL (/api/graphql) |
Clone externa-bruno, open that folder in Bruno, select env Local, copy .env.sample → .env and set EXTERNA_API_KEY (and base_url if not on http://externa-core.test). For staging, duplicate Local and change base_url + key. Endpoint examples live in the docs (Public CMS API, GraphQL); Bruno executes them.
Next steps
- Deeper local setup & troubleshooting: Installation
- Tune every key: Environment variables
- Minimal vs Redis stack: Minimal vs full stack
- Code map: Project layout
- Access control: Effective permissions
- Headless API: Public CMS API · GraphQL
- Try requests: externa-bruno