Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
92 lines
3.7 KiB
Bash
92 lines
3.7 KiB
Bash
#!/bin/sh
|
|
set -e
|
|
|
|
###############################################################################
|
|
# Everything that has to be true before the application answers a request.
|
|
#
|
|
# Runs in every container built from this image, but not every container is a
|
|
# service: `docker compose run app php artisan key:generate` has to work on a
|
|
# stack that has never been started, which is exactly when there is no APP_KEY
|
|
# and no database yet. So the preparation below applies to the three
|
|
# long-running commands, and anything else is passed straight through.
|
|
###############################################################################
|
|
|
|
case "$*" in
|
|
frankenphp*|*queue:work*|*schedule:work*) is_service=true ;;
|
|
*) is_service=false ;;
|
|
esac
|
|
|
|
# A named volume mounted over storage/ starts as a copy of the image's, but a
|
|
# bind mount does not, and neither survives a container being recreated with an
|
|
# empty one. Cheap to guarantee, expensive to debug — and needed by one-off
|
|
# commands too, since most of them write a log.
|
|
mkdir -p \
|
|
storage/app/public \
|
|
storage/framework/cache/data \
|
|
storage/framework/sessions \
|
|
storage/framework/views \
|
|
storage/logs
|
|
|
|
chown -R www-data:www-data storage bootstrap/cache 2>/dev/null || true
|
|
|
|
if [ "$is_service" = "false" ]; then
|
|
exec "$@"
|
|
fi
|
|
|
|
if [ -z "${APP_KEY}" ]; then
|
|
echo "APP_KEY is not set. Generate one with:" >&2
|
|
echo " docker compose run --rm --no-deps app php artisan key:generate --show" >&2
|
|
echo "Without it sessions cannot be decrypted and preview links cannot be signed." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Wait for Postgres rather than crash-looping against it. Compose's own
|
|
# healthcheck covers the ordinary case; this covers the database restarting
|
|
# under a running application.
|
|
if [ "${DB_CONNECTION:-pgsql}" = "pgsql" ]; then
|
|
tries=0
|
|
until pg_isready -h "${DB_HOST:-postgres}" -p "${DB_PORT:-5432}" -U "${DB_USERNAME:-pireon}" -q; do
|
|
tries=$((tries + 1))
|
|
if [ "$tries" -ge 30 ]; then
|
|
echo "Database at ${DB_HOST:-postgres}:${DB_PORT:-5432} never became ready." >&2
|
|
exit 1
|
|
fi
|
|
echo "Waiting for the database… (${tries}/30)"
|
|
sleep 2
|
|
done
|
|
fi
|
|
|
|
# Opt-in rather than automatic: a migration is a change to somebody's data, and
|
|
# on a multi-container deploy it must run once, not once per container. Set it
|
|
# on the web service only.
|
|
if [ "${RUN_MIGRATIONS}" = "true" ]; then
|
|
echo "Running migrations…"
|
|
# CACHE_STORE is overridden for this one command, not passed to
|
|
# `--isolated` — that option's value is only an exit code, never a store.
|
|
#
|
|
# It matters because with CACHE_STORE=database the lock table is created by
|
|
# these very migrations, so on a brand new database the lock would be taken
|
|
# against a table that does not exist yet and the container would crash-loop
|
|
# for ever. The file store lives on the shared storage volume, so it still
|
|
# stops two containers migrating at once.
|
|
CACHE_STORE=file php artisan migrate --force --isolated
|
|
|
|
# The permission catalogue is code, so a deploy that adds one has to sync
|
|
# it or the new permission exists nowhere.
|
|
php artisan permissions:sync
|
|
fi
|
|
|
|
# Serves uploaded images from the storage volume. Idempotent, and it has to run
|
|
# here rather than at build time because the volume is mounted after the image
|
|
# is built.
|
|
php artisan storage:link --quiet 2>/dev/null || true
|
|
|
|
# Config, routes and views compiled once per container start. This is most of
|
|
# the difference between an API answering in 4ms and in 40, which matters when
|
|
# an SSR frontend makes several calls per page view.
|
|
php artisan config:cache --quiet
|
|
php artisan route:cache --quiet
|
|
php artisan view:cache --quiet
|
|
|
|
exec "$@"
|