# Production deployment

## Web server

Point the web server document root at the project's `public` directory. Do not expose the repository root: it contains `.env`, source code, and dependencies.

For Apache, enable `mod_rewrite` and allow overrides for `public/.htaccess`. For Nginx, route unknown requests to `public/index.php` and deny access to dot files.

## Environment

1. Copy `.env.example` to `.env`.
2. Set `APP_ENV=production`, `APP_DEBUG=false`, a unique `APP_KEY`, and the public HTTPS `APP_URL`.
3. Configure a non-root database user, mail transport, and a shared cache/session/queue backend when using more than one web node.
4. Set `VITE_ASSET_BASE=/build/` when the document root is `public`. For a subdirectory deployment, set it to the public URL prefix, for example `/my-app/build/`.

## Build and release

Run these commands from the release directory:

```text
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan storage:link
npm ci
npm run build
php artisan optimize
```

The `storage`, `bootstrap/cache`, and `public/build` directories must be writable by the deployment user. The web user needs write access to `storage` and `bootstrap/cache`, but the repository root should remain outside the web root.

## Workers and scheduler

Run a queue worker continuously and restart it after each release:

```text
php artisan queue:work --sleep=3 --tries=3 --timeout=90
```

Run Laravel's scheduler every minute:

```text
* * * * * cd /path/to/project && php artisan schedule:run >> /dev/null 2>&1
```

## Health checks

After deployment, verify the public URL, login page, asset URLs, uploads, mail delivery, queue processing, and `php artisan about`. Never leave the installer accessible after installation; remove `storage/installed` only during a controlled reinstall because it triggers the installation flow.
