Overview

The installer plugin is a first-party package that gives a fresh Qcentic Edge deploy a first-run web UI at /install. It targets hosts with ephemeral disks and no shell — bunny.net Magic Containers — where php artisan migrate is not an option. The operator drives setup from the browser, then retires the installer with an env flip.

Flow

/install renders a checklist of environment and runtime checks (InstallerState::checks()): required env keys filled, database reachable, storage/app writable, pending migrations counted. When every check is ok, Run is enabled. The controller then runs migrate --force, the seeder classes listed in installer.seeders, and — when installer.create_user is true — creates the first user, dispatching InstallerUserCreated. Finally it inserts one row into installer_locks and redirects to the Complete page.

While unlocked

Before the lock row exists, the service provider forces session.driver = cookie and cache.default = array. The sessions and cache tables do not exist yet, so the database stores would 500. Cookie sessions ride the request; array cache lives in memory. Once installer_locks has a row, the app keeps redirecting to /install until the operator sets INSTALLER_ENABLED=false and redeploys.

The redirect middleware never traps Vite (_vite*), Livewire (livewire/* and the hashed livewire-{id}/… paths), or /up — so assets and health checks keep working during install.

The lock

The lock is a row in the shared installer_locks table (id, installed_at), not a file on disk. Any replica that can read the database sees the same installed state, which is what makes the installer safe on multi-pod stateless hosts.

flowchart TD
    A["/install checklist"] -->|Run| B["migrate --force"]
    B --> C["seeders via installer.seeders"]
    C --> D{create_user?}
    D -->|yes| E["First user + InstallerUserCreated"]
    D -->|no| F["Insert installer_locks row"]
    E --> F
    F --> G["Complete page"]
    G --> R{env still true?}
    R -->|yes| G
    R -->|INSTALLER_ENABLED=false + redeploy| H["App open"]

See also

  • Two gates — the lock row and the env retire switch, and why both are required.
  • Host wiringinstaller.seeders, InstallerUserCreated, and the env keys the checklist reads.
  • First-run installer guide — operator walkthrough from deploy to app open.
Built by Qcentic