- Added public gallery API with token-expiry enforcement, branding payload, cursor pagination, and per-photo download stream (app/Http/Controllers/Api/EventPublicController.php:1, routes/api.php:16). 410 is returned when the package gallery duration has lapsed.

- Served the guest PWA at /g/{token} and introduced a mobile-friendly gallery page with lazy-loaded thumbnails, themed colors, lightbox, and download links plus new gallery data client (resources/js/guest/pages/PublicGalleryPage.tsx:1, resources/js/guest/services/galleryApi.ts:1, resources/js/guest/router.tsx:1). Added i18n strings for the public gallery experience (resources/js/guest/i18n/messages.ts:1).
- Ensured checkout step changes snap back to the progress bar on mobile via smooth scroll anchoring (resources/ js/pages/marketing/checkout/CheckoutWizard.tsx:1).
- Enabled tenant admins to export all approved event photos through a new download action that streams a ZIP archive, with translations and routing in place (app/Http/Controllers/Tenant/EventPhotoArchiveController.php:1, app/Filament/Resources/EventResource.php:1, routes/web.php:1, resources/lang/de/admin.php:1, resources/lang/en/admin.php:1).
This commit is contained in:
Codex Agent
2025-10-17 23:24:06 +02:00
parent 5817270c35
commit ae9b9160ac
20 changed files with 1410 additions and 3 deletions

109
docs/deployment/docker.md Normal file
View File

@@ -0,0 +1,109 @@
# Docker Deployment Guide
This guide describes the recommended, repeatable way to run the Fotospiel platform in Docker for production or high-fidelity staging environments. It pairs a multi-stage build (PHP-FPM + asset pipeline) with a Compose stack that includes Nginx, worker processes, Redis, and MySQL.
## 1. Prerequisites
- Docker Engine 24+ and Docker Compose v2.
- A `.env` file for the application (see step 4).
- Optional: an external MySQL/Redis if you do not want to run the bundled containers.
## 2. Build the application image
```bash
docker compose build app
```
The build performs the following steps:
1. Installs Node dependencies and runs `npm run build` to produce production assets.
2. Installs PHP dependencies with Composer (`--no-dev --no-scripts`).
3. Creates a PHP 8.3 FPM image with required extensions (GD, intl, Redis, etc.).
4. Stores the compiled application under `/opt/app`; the runtime entrypoint syncs it into the shared volume when a container starts.
## 3. Configure environment
Copy the sample Docker environment file and edit the secrets:
```bash
cp docker/.env.docker docker/.env.docker.local
```
Set (at minimum):
- `APP_KEY` — generate with `docker compose run --rm app php artisan key:generate --show`.
- Database credentials (`DB_*`). The provided MySQL service defaults to `fotospiel/secret`.
- `STORAGE_ALERT_EMAIL` — recipient for upload failure alerts (optional).
Point `docker-compose.yml` to the file you created by either renaming it to `docker/.env.docker` or adjusting the `env_file` entries.
## 4. Boot the stack
```bash
docker compose up -d
```
Services started:
- `app`: PHP-FPM container serving the Laravel application.
- `web`: Nginx proxy forwarding requests to PHP-FPM on port `8080` by default (`APP_HTTP_PORT`).
- `queue` & `media-storage-worker`: queue consumers (default + media archival).
- `scheduler`: runs `php artisan schedule:work`.
- `horizon` (optional, disabled unless `--profile horizon` is supplied).
- `redis` & `mysql`.
### Migrations & seeds
Run once after the first boot or when deploying new schema changes:
```bash
docker compose exec app php artisan migrate --force
docker compose exec app php artisan db:seed --class=MediaStorageTargetSeeder --force
```
If you already have data, skip the seeder or seed only new records.
## 5. Queue & Horizon management
Worker entrypoints live in `docs/queue-supervisor/`. The Compose services mount the same application volume so code stays in sync. Adjust concurrency by scaling services:
```bash
docker compose up -d --scale queue=2 --scale media-storage-worker=2
```
To enable Horizon (dashboard, smart balancing):
```bash
docker compose --profile horizon up -d horizon
```
The dashboard becomes available at `/horizon` and is protected by the Filament super-admin auth guard.
## 6. Persistent data & volumes
- `app-code` — contains the synced application, including the `storage` directory and generated assets.
- `mysql-data` — MySQL data files.
- `redis-data` — Redis persistence (disabled by default; change the Redis command if you want AOF snapshots).
Back up the volumes before upgrades to maintain tenant media and database state.
## 7. Updating the stack
1. `git pull` the repository (or deploy your release branch).
2. `docker compose build app`.
3. `docker compose up -d`.
4. Run migrations + seeders if required.
5. Check logs: `docker compose logs -f app queue media-storage-worker`.
Because the app image keeps the authoritative copy of the code, each container restart rsyncs fresh sources into the shared volume ensuring reliable updates without lingering artefacts.
## 8. Production hardening
- Terminate TLS with a dedicated reverse proxy (Traefik, Caddy, AWS ALB, etc.) in front of the `web` container.
- Point `APP_URL` to your public domain and enable trusted proxies.
- Externalize MySQL/Redis to managed services for better resilience.
- Configure backups for the `storage` directories and database dumps.
- Hook into your observability stack (e.g., ship container logs to Loki or ELK).
With the provided configuration you can bootstrap a consistent Docker-based deployment across environments while keeping queue workers, migrations, and asset builds manageable. Adjust service definitions as needed for staging vs. production.

View File

@@ -0,0 +1,103 @@
## Docker Queue & Horizon Setup
This directory bundles ready-to-use entrypoint scripts and deployment notes for running Fotospiels queue workers inside Docker containers. The examples assume you already run the main application in Docker (e.g. via `docker-compose.yml`) and share the same application image for workers.
### 1. Prepare the application image
Make sure the worker scripts are copied into the image and marked as executable:
```dockerfile
# Dockerfile
COPY docs/queue-supervisor /var/www/html/docs/queue-supervisor
RUN chmod +x /var/www/html/docs/queue-supervisor/*.sh
```
If you keep the project root mounted as a volume during development the `chmod` step can be skipped because the files will inherit host permissions.
### 2. Queue worker containers
Add one or more worker services to `docker-compose.yml`. The production compose file in the repo already defines `queue` and `media-storage-worker` services that call these scripts; the snippet below shows the essential pattern if you need to tweak scaling.
```yaml
services:
queue-worker:
image: fotospiel-app # reuse the main app image
restart: unless-stopped
depends_on:
- redis # or your queue backend
environment:
APP_ENV: ${APP_ENV:-production}
QUEUE_CONNECTION: redis
QUEUE_TRIES: 3 # optional overrides
QUEUE_SLEEP: 3
command: >
/var/www/html/docs/queue-supervisor/queue-worker.sh default
media-storage-worker:
image: fotospiel-app
restart: unless-stopped
depends_on:
- redis
environment:
APP_ENV: ${APP_ENV:-production}
QUEUE_CONNECTION: redis
QUEUE_TRIES: 5
QUEUE_SLEEP: 5
command: >
/var/www/html/docs/queue-supervisor/queue-worker.sh media-storage
```
Scale workers by increasing `deploy.replicas` (Swarm) or adding `scale` counts (Compose v2).
### 3. Optional: Horizon container
If you prefer Horizons dashboard and auto-balancing, add another service:
```yaml
services:
horizon:
image: fotospiel-app
restart: unless-stopped
depends_on:
- redis
environment:
APP_ENV: ${APP_ENV:-production}
QUEUE_CONNECTION: redis
command: >
/var/www/html/docs/queue-supervisor/horizon.sh
```
Expose Horizon via your web proxy and protect it with authentication (the app already guards `/horizon` behind the super admin panel login if configured).
### 4. Environment variables
- `QUEUE_CONNECTION` — should match the driver configured in `.env` (`redis` recommended).
- `QUEUE_TRIES`, `QUEUE_SLEEP`, `QUEUE_TIMEOUT`, `QUEUE_MAX_TIME` — optional tuning knobs consumed by `queue-worker.sh`.
- `STORAGE_ALERT_EMAIL` — enables upload failure notifications introduced in the new storage pipeline.
- Redis / database credentials must be available in the worker containers exactly like the web container.
### 5. Bootstrapping reminder
Before starting workers on a new environment:
```bash
php artisan migrate
php artisan db:seed --class=MediaStorageTargetSeeder
```
Existing assets should be backfilled into `event_media_assets` with a one-off artisan command before enabling automatic archival jobs.
### 6. Monitoring & logs
- Containers log to STDOUT; aggregate via `docker logs` or a centralized stack.
- Horizon users can inspect `/horizon` for queue lengths and failed jobs.
- With plain workers run `php artisan queue:failed` (inside the container) to inspect failures and `php artisan queue:retry all` after resolving issues.
### 7. Rolling updates
When deploying new code:
1. Build and push updated app image.
2. Run migrations & seeders.
3. Recreate worker/horizon containers: `docker compose up -d --force-recreate queue-worker media-storage-worker horizon`.
4. Tail logs to confirm workers boot cleanly and start consuming jobs.

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Horizon entrypoint for Docker containers.
set -euo pipefail
cd "${APP_PATH:-/var/www/html}"
echo "[horizon] Booting Horizon..."
exec php artisan horizon

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Generic queue worker entrypoint for Docker containers.
# Usage: queue-worker.sh [queue-name(s)]
# Example: queue-worker.sh default
# queue-worker.sh default,media-storage
set -euo pipefail
cd "${APP_PATH:-/var/www/html}"
CONNECTION="${QUEUE_CONNECTION:-redis}"
QUEUES="${1:-default}"
SLEEP="${QUEUE_SLEEP:-3}"
TRIES="${QUEUE_TRIES:-3}"
TIMEOUT="${QUEUE_TIMEOUT:-60}"
MAX_TIME="${QUEUE_MAX_TIME:-0}"
ARGS=("$CONNECTION" "--queue=${QUEUES}" "--sleep=${SLEEP}" "--tries=${TRIES}" "--timeout=${TIMEOUT}")
if [[ "${MAX_TIME}" != "0" ]]; then
ARGS+=("--max-time=${MAX_TIME}")
fi
echo "[queue-worker] Starting queue:work ${ARGS[*]}"
exec php artisan queue:work "${ARGS[@]}"