Skip to content

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:

  1. The backend (apps/backend-laravel), installed with composer install --no-dev.
  2. The built console (apps/web-aurelia/dist).
  3. 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.

  1. Check out the release tag and run the checks from testing.
  2. Build the console: npm install && npm run web:build.
  3. Stage the backend: composer install --no-dev --optimize-autoloader in a clean copy.
  4. Upload the backend and dist to the server. Leave .env, storage/, bootstrap/cache/, plugins/ and themes/ alone. They belong to the installation, not the release. See upgrading.
  5. 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
  6. Reload php-fpm so opcache sees the new files, and restart Reverb.
  7. Check /up returns "status":"ok" (the scheduler line may say unknown for 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:

  1. Refuses a dirty working tree. What's deployed must match the commit it reports.
  2. 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) and VITE_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.
  3. Builds the docs with npm run docs:build (VitePress, from docs/) for /docs/. Internal notes such as the code audit and the research documents are left out; the list is srcExclude in docs/.vitepress/config.mts.
  4. Builds the field app for web with expo export --clear and the demo's API address and technician login. --clear matters, because Metro caches inlined variables and would ship the old API address. It then pre-compresses the files so nginx serves the .gz copies.
  5. Stages the backend from git archive HEAD, runs composer install --no-dev, and writes the commit into REVISION.
  6. Uploads with rsync --delete, excluding .env, storage/, bootstrap/cache/, the demo credentials file, the SQLite file and tests.
  7. 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-horizon and waste-reverb services. Horizon runs every queue (PDFs, syncs and webhooks included), and the script prints horizon:status and warns if it isn't running. It also warns if cron isn't running, because the nightly reset and the scheduler depend on it.
  8. Checks that /, /field/, /docs/ and /up return a status, and prints the /up report (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 ​

DemoReal install
MySQL 8 and the predis client, because the host has no pgsql or phpredis extensionYour choice of Postgres or MySQL
DEMO_READ_ONLY=true. Every write except sign-in is refusedOff
MAIL_MAILER=log, so nothing is emailedA real mail setup
Auto sign-in baked into the consoleNeeds a sign-in solution. See API
Nightly reseed from cronNever reseed a real database
nginx rate limiting and noindex headersYour 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.

A$125 a month, or A$9,450 once with the source code. Contact us.