Appearance
Deploy
There are two things on this page: the shipping script the repository includes, which deploys the public demo, and the general steps for putting a release on your own server. The demo script is a good worked example of the second.
What a release is
A release is three pieces that have to match:
- The backend (
apps/backend-laravel), installed withcomposer install --no-dev. - The built console (
apps/web-aurelia/dist). - Optionally the field app, built for web (
expo export) or distributed as a phone app.
The database migrates forward with php artisan migrate --force. Migrations also run any installed plugin's pending migrations.
Deploying your own server
Build on a machine that has Node, and ship the output. The server only needs PHP.
- Check out the release tag and run the checks from testing.
- Build the console:
npm install && npm run web:build. - Stage the backend:
composer install --no-dev --optimize-autoloaderin a clean copy. - Upload the backend and
distto the server. Leave.env,storage/,bootstrap/cache/,plugins/andthemes/alone. They belong to the installation, not the release. See upgrading. - On the server:bash
cd apps/backend-laravel php artisan down # optional, for a quiet moment php artisan migrate --force php artisan optimize:clear php artisan config:cache && php artisan route:cache # optional php artisan rangefront:plugin:list # anything needing attention php artisan horizon:terminate # the supervisor restarts it on the new code php artisan up - Reload php-fpm so opcache sees the new files, and restart Reverb.
- Check
/upreturns"status":"ok"(the scheduler line may sayunknownfor the first minute) and sign in. See install.
Keep the previous release folder until you're happy with the new one. Migrations only go forward in normal use, so take a database backup first (see backup and restore).
Don't leave phpunit.xml, phpstan.neon or tests/ on a production server.
The demo script
npm run demo:deploy runs scripts/deploy-demo.sh. It ships the current commit to the public demo at waste.rangefrontlabs.com.au on the server voldemort and reseeds it. DEMO-APP.md at the repo root describes how that server is laid out.
What the script does, in order:
- Refuses a dirty working tree. What's deployed must match the commit it reports.
- Builds the console with the demo login switched on and baked in (
VITE_FORCE_DEMO_LOGIN,VITE_ENABLE_DEMO_LOGIN,VITE_FIELD_APP_URL=/field/,VITE_DEMO_EMAIL,VITE_DEMO_PASSWORD) andVITE_DEMO_BANNER=true, which adds a thin strip above the console with the price and links to the docs and the contact page. It checks the bundle contains the demo account. - Builds the docs with
npm run docs:build(VitePress, fromdocs/) for/docs/. Internal notes such as the code audit and the research documents are left out; the list issrcExcludeindocs/.vitepress/config.mts. - Builds the field app for web with
expo export --clearand the demo's API address and technician login.--clearmatters, because Metro caches inlined variables and would ship the old API address. It then pre-compresses the files so nginx serves the.gzcopies. - Stages the backend from
git archive HEAD, runscomposer install --no-dev, and writes the commit intoREVISION. - Uploads with
rsync --delete, excluding.env,storage/,bootstrap/cache/, the demo credentials file, the SQLite file and tests. - On the server, fixes ownership and permissions, rediscovers packages, clears caches, runs the demo reset script (a fresh migrate and seed, then the demo credentials), reloads php-fpm and restarts the
waste-horizonandwaste-reverbservices. Horizon runs every queue (PDFs, syncs and webhooks included), and the script printshorizon:statusand warns if it isn't running. It also warns if cron isn't running, because the nightly reset and the scheduler depend on it. - Checks that
/,/field/,/docs/and/upreturn a status, and prints the/upreport (database, Redis, queue backlog and scheduler heartbeat).
The variables DEMO_HOST, DEMO_DOMAIN and DEMO_PASSWORD override its defaults. The demo logins are public on purpose.
How the demo differs from a real install
| Demo | Real install |
|---|---|
MySQL 8 and the predis client, because the host has no pgsql or phpredis extension | Your choice of Postgres or MySQL |
DEMO_READ_ONLY=true. Every write except sign-in is refused | Off |
MAIL_MAILER=log, so nothing is emailed | A real mail setup |
| Auto sign-in baked into the console | Needs a sign-in solution. See API |
| Nightly reseed from cron | Never reseed a real database |
nginx rate limiting and noindex headers | Your own policy |
The server shape
For reference, the demo uses nginx and php-fpm directly, with this layout:
text
/var/www/<host>/backend Laravel
/var/www/<host>/web the built console
/var/www/<host>/fieldapp the field app web export, served at /field/nginx serves the console at /, passes /api, /sanctum, /broadcasting, /storage and /up to PHP, and proxies /app/ to Reverb on 127.0.0.1:8080. Two systemd units run php artisan horizon and php artisan reverb:start. The scheduler runs from cron every minute.
A web build of the field app needs two extra headers on /field/ (Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp) and a .wasm MIME type, because the local database runs as WebAssembly in the browser.
Other infrastructure scripts
infra/local-dev/docker-compose.yml is for development only. It isn't a production recipe. There are no other deploy scripts in the repository. The shipping script above, DEMO-APP.md and this page are the whole deploy story.