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

RequirementNotes
PHP 8.4Pinned in .php-version / composer.json (^8.4). Use Herd’s PHP 8.4 CLI.
Composer 2PHP dependencies and composer setup / composer run dev.
Node.js 24Pinned in .nvmrc and package.json engines. Run nvm use (or equivalent).
Laravel HerdServes 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 installnpm 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:

  1. PermissionSeeder — syncs Spatie permissions from PermissionEnum via php artisan permissions:sync
  2. RoleSeeder — roles:
    RoleNotes
    super-adminEvery Spatie permission
    adminEvery Spatie permission
    readerOnly can-show-* permissions
    publicSystem role (is_system, not assignable); no Spatie admin permissions — used for anonymous Public CMS API; grant collection/file access in the role UI
  3. CreateSuperAdminSeeder — first user from config/super_admin.php
Default (local only)
Emailsuperadmin@example.com
Passwordpassword

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

NeedOne-linerDocs
RedisEnable in Herd; keep REDIS_* as aboveRedis
Horizonphp artisan horizonHorizon
Reverb + EchoHerd Pro on :8080 + REVERB_* / VITE_REVERB_*Reverb & Echo
Pulsephp artisan pulse:work (redis ingest)Pulse & Health
Queues / schedulerOps overviewOperations
RepoRole
externa-coreLaravel + Inertia app (this Quick Start)
externa-docsProduct docs (this site)
externa-brunoRunnable 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

Previous
Introduction