Initial commit: Pireon Admin — headless admin panel and public API
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>
This commit is contained in:
91
docker/entrypoint.sh
Normal file
91
docker/entrypoint.sh
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/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 "$@"
|
||||
Reference in New Issue
Block a user