Skip to content

Admin Workflows

This page covers the development workflows for the Laravel 13 admin app — running the local Docker stack, bootstrapping users, and working with ingestion.

Prerequisites

  • Docker (for the full local stack)
  • PHP 8.4+ and Composer (if running outside Docker)
  • pnpm (for JS assets)

Starting the local stack

The admin app uses compose.production.yaml as the base with a compose.local.yaml overlay for local-only services.

Full Docker stack

bash
cd apps/admin
docker compose -f compose.production.yaml -f compose.local.yaml up -d

Or from the monorepo root:

bash
pnpm run docker:admin:local:up

This starts the local admin stack, including FrankenPHP, PostgreSQL, Redis, Horizon, Traefik, and the supporting services defined by the compose files.

Local URL: https://localhost/admin

The local stack runs over HTTPS with a self-signed certificate. Accept the browser warning or add it to your trusted certs.

App process only

If PostgreSQL, Redis, and the rest of the stack are already running, you can start just the Laravel app and Vite watcher:

bash
cd apps/admin
composer install
composer dev

This path does not provision PostgreSQL, Redis, Horizon, or Traefik. In the checked-in local admin setup, this mode typically runs from http://localhost:8000.

Running migrations

Run migrations before seeding roles or bootstrapping users:

bash
# Inside the container
docker compose -f compose.production.yaml -f compose.local.yaml exec -T app php artisan migrate

# Locally (without Docker)
cd apps/admin && php artisan migrate

Bootstrapping the first admin user

The Filament panel does not seed a default user. After migrations complete, bootstrap your first admin from the running container:

bash
cd apps/admin
docker compose -f compose.production.yaml -f compose.local.yaml exec -T app php artisan db:seed --class=AdminRoleSeeder

docker compose -f compose.production.yaml -f compose.local.yaml exec -T app php artisan tinker --execute="\$user = \App\Models\User::updateOrCreate(['email' => '[email protected]'], ['name' => 'Kubuli Admin', 'password' => 'kubuli_admin_password']); \$user->syncRoles(['admin']);"

Sign in at https://localhost/admin/login with [email protected] / kubuli_admin_password.

To test curator-only flows:

bash
docker compose -f compose.production.yaml -f compose.local.yaml exec -T app php artisan tinker --execute="\$user = \App\Models\User::updateOrCreate(['email' => '[email protected]'], ['name' => 'Kubuli Curator', 'password' => 'kubuli_curator_password']); \$user->syncRoles(['curator']);"

Queue workers (Horizon)

The Docker stack includes a dedicated Horizon container. If you are running only the Laravel app process locally, start Horizon separately:

bash
php artisan horizon

Environment variables

bash
cp apps/admin/.env.example apps/admin/.env
php artisan key:generate

Key variables for local development:

bash
APP_URL=https://localhost
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=kubuli
DB_USERNAME=postgres
DB_PASSWORD=password
QUEUE_CONNECTION=redis
N8N_API_URL=http://n8n:25678
N8N_API_KEY=       # Set from your local n8n instance before provisioning workflows

The checked-in .env.example uses host-reachable values for local host-run commands. When you exec into the Dockerized app, the compose stack provides the container-side database and service networking automatically.

n8n in development

The local Docker stack exposes n8n at http://localhost:25678. If you are using the full Docker stack above, no extra compose profile is required.

→ Full ingestion reference: Ingestion & Review

Running admin tests

bash
# From apps/admin
php artisan test

# With coverage
php artisan test --coverage

Built with VitePress