Dev #9

Merged
LordSchmackes merged 13 commits from dev into main 2026-05-23 21:30:54 +00:00
10 changed files with 624 additions and 3 deletions
Showing only changes of commit 054141020d - Show all commits
@@ -0,0 +1,324 @@
---
name: Coolify React CMS Stack
overview: "Empfohlener Standard-Stack: Next.js (React) + Payload CMS (self-hosted) + PostgreSQL, alles als Docker-Images über GitHub → Coolify. Cursor/MCP für die Entwicklung, GitHub Actions für Qualitätssicherung vor dem Deploy."
todos:
- id: scaffold-monorepo
content: "Greenfield-Monorepo anlegen: apps/web (Next standalone), apps/cms (Payload), packages/shared-types"
status: pending
- id: docker-coolify
content: "Dockerfiles, docker-compose.yml, docs/COOLIFY.md (3 Services: Postgres, CMS, Web) nach FlixCooks-Muster"
status: pending
- id: cms-content-model
content: Payload Collections + Webhooks für On-Demand Revalidation; Env-Beispiele in .env.example
status: pending
- id: github-ci
content: "GitHub Actions: lint, typecheck, build, docker build smoke; branch protection auf main"
status: pending
- id: mcp-agents
content: .cursor/mcp.json + .agents/brain.md mit Stack-, Env- und Deploy-Regeln für KI
status: pending
- id: animation-baseline
content: "GSAP/Lenis/Framer-Baseline-Komponenten und Regel: Overlays stoppen Lenis"
status: pending
isProject: false
---
# Tech-Stack & Workflow: React-Sites, CMS, Docker, Coolify
## Empfehlung (Default)
Du bist unsicher bei CMS und Frontend hier ist ein **bewährtes Default**, das zu deinen Vorgaben passt (React, Animationen, Docker, Coolify, KI/MCP, CI):
| Schicht | Technologie | Warum |
|---------|-------------|--------|
| **Frontend** | [Next.js 15](https://nextjs.org) (App Router, TypeScript) | SEO/SSR/ISR, React-Ökosystem, `output: 'standalone'` für ein schlankes Production-Docker-Image |
| **Animationen** | GSAP (+ ScrollTrigger), Framer Motion, Lenis | GSAP für Scroll/Timeline-Premium-Feel; Framer für UI-Micro-Interactions; Lenis kennst du bereits aus FlixCooks |
| **CMS** | [Payload CMS 3](https://payloadcms.com) (eigener Container) | TypeScript, Postgres-native, Admin-UI out of the box, Docker-freundlich, passt zu Coolify wie dein aktuelles Postgres-Setup |
| **Datenbank** | PostgreSQL 16 (Coolify Database Service) | Eine Instanz, getrennte DBs/User für CMS vs. App optional |
| **Runtime / Deploy** | Docker + [Coolify](https://coolify.io) | Git-Webhook → Build → Traefik/HTTPS; du hast das Muster schon in [docs/COOLIFY.md](docs/COOLIFY.md) |
| **Lokale Dev** | `docker compose` (Web + CMS + Postgres) | Parität zu Production, wie [docker-compose.yml](docker-compose.yml) bei FlixCooks |
| **KI-Entwicklung** | Cursor + MCP-Server | Repo-Kontext, GitHub, Docs, optional DB |
| **CI** | GitHub Actions | Lint, Types, Build, Docker-Smoke, optional E2E; PR-Review wie [.github/workflows/gemini-pr-review.yml](.github/workflows/gemini-pr-review.yml) |
**Alternative Frontend:** Vite + React SPA + nginx-Image maximal frei für reine Animation-Landingpages, aber schlechteres SEO und kein ISR ohne Extra-Aufwand. **Alternative CMS (weniger Ops):** Sanity/Contentful (Cloud) nur Frontend-Container auf Coolify. **Alternative CMS (kein Backend):** Tina/Decap + Markdown im Repo gut für Blogs, schwächer für Redakteur:innen ohne Git.
---
## Zielarchitektur auf Coolify
```mermaid
flowchart TB
subgraph dev [Entwicklung]
Cursor[Cursor + MCP]
LocalCompose[docker compose]
Cursor --> LocalCompose
end
subgraph github [GitHub]
Repo[Monorepo]
GHA[GitHub Actions CI]
Repo --> GHA
end
subgraph coolify [Coolify Server]
PG[(PostgreSQL)]
CMS[Payload CMS Container]
WEB[Next.js Container]
Traefik[Traefik HTTPS]
PG --> CMS
CMS -->|REST/GraphQL| WEB
Traefik --> WEB
Traefik --> CMS
end
dev -->|push main| Repo
GHA -->|grüner Build| Repo
Repo -->|Webhook Deploy| coolify
```
**Drei Coolify-Ressourcen** (analog zu deinem FlixCooks-Setup: Postgres + App):
1. **PostgreSQL** internal URL, nicht öffentlich
2. **CMS-App** Dockerfile aus `apps/cms`, Port z. B. 3001, Env: `DATABASE_URL`, `PAYLOAD_SECRET`
3. **Web-App** Dockerfile aus `apps/web`, Port 3000, Env: `CMS_URL` (internal), `REVALIDATE_SECRET` für On-Demand-ISR
Persistenz: Postgres-Volume (Inhalte), optional Volume für CMS-Uploads (`/app/media`).
---
## Repository-Struktur (Greenfield-Vorlage)
Ein Repo pro „Site-Familie“ oder Monorepo für mehrere Marken:
```
my-site/
├── apps/
│ ├── web/ # Next.js
│ │ ├── Dockerfile
│ │ ├── src/
│ │ └── next.config.ts # output: 'standalone'
│ └── cms/ # Payload
│ ├── Dockerfile
│ └── payload.config.ts
├── packages/
│ └── shared-types/ # optional: gemeinsame TS-Typen CMS ↔ Web
├── docker-compose.yml # lokaler Prod-Parität-Stack
├── docker-compose.dev.yml # nur Postgres (wie bei FlixCooks)
├── .github/workflows/
│ ├── ci.yml
│ └── gemini-pr-review.yml # optional, aus FlixCooks übernehmen
├── .cursor/
│ └── mcp.json # MCP-Server für das Team
├── .agents/
│ ├── brain.md # Architektur für KI (Pattern aus FlixCooks)
│ └── rules/AGENT.md
└── docs/
└── COOLIFY.md
```
---
## Frontend-Stack (React + Animationen)
**Kern:**
- **Next.js App Router** Seiten in `app/`, Server Components für CMS-Daten, Client Components nur für Animation/Interaktion
- **TypeScript** strikt; Typen aus Payload generieren (`payload generate:types`)
- **Styling** CSS Modules oder Tailwind (nur wenn du es willst; FlixCooks bleibt bei Vanilla CSS für neue React-Sites ist Tailwind optional, nicht Pflicht)
**Animation-Toolkit:**
| Tool | Einsatz |
|------|---------|
| **GSAP + ScrollTrigger** | Hero-Sequences, pinned Sections, komplexe Timelines |
| **Framer Motion** | Hover, Page-Transitions, modale UI |
| **Lenis** | Smooth Scroll (wie FlixCooks: bei Overlays `lenis.stop()`) |
| **(optional) @react-three/fiber** | 3D-Hero nur wenn nötig |
**CMS-Anbindung im Web:**
- **Build-Zeit (SSG):** `generateStaticParams` + Fetch von Payload REST für Marketing-Seiten
- **On-Demand Revalidation:** Payload-Webhook → `POST /api/revalidate?secret=...` in Next.js (Inhalt ändert sich ohne Full-Redeploy)
- **Preview:** Draft-Modus mit Payload Preview-URL + Next `draftMode()`
Env im Web-Container (Coolify):
- `CMS_URL=http://payload-service:3001` (internal hostname)
- `REVALIDATE_SECRET`, `NEXT_PUBLIC_SITE_URL`
---
## CMS-Stack (Payload auf Coolify)
**Warum Payload als Default:** Self-hosted, eine Postgres-URL, Admin unter `/admin`, Collections/Blocks für Seitenmodule, Media-Uploads, Webhooks alles containerisierbar.
**Coolify Env (CMS):**
- `DATABASE_URL` internal Postgres URL (gleiches Muster wie [docs/COOLIFY.md](docs/COOLIFY.md) Zeilen 3343)
- `PAYLOAD_SECRET` langer Zufallswert (nur Secrets, nie ins Repo)
- `NEXT_PUBLIC_SERVER_URL` öffentliche CMS-URL (für Admin-Assets)
**Erstes Deployment:** analog FlixCooks `RUN_DB_SEED` einmalig Migration/Seed, danach Flag entfernen.
**Sicherheit:** CMS-Admin nur über HTTPS; CORS auf Web-Domain beschränken; API-Keys für Preview/Revalidate nur als Secrets.
---
## Docker-Images
### Web (`apps/web/Dockerfile`) Next standalone
Mehrstufig: `node:22-alpine``npm ci``npm run build` → Runtime nur `.next/standalone` + `static` + `public`.
- `EXPOSE 3000`
- `HEALTHCHECK` auf `/api/health` (kleine Route: `{ "status": "ok" }`)
- Coolify: Port **3000**, Health Path `/api/health`
### CMS (`apps/cms/Dockerfile`)
Payload-Official-Pattern oder Node-Image mit `npm run build && npm run start`.
- `HEALTHCHECK` auf CMS-Health-Endpoint
- Volume für `/app/media` (Uploads überleben Redeploy)
### Lokales Parität-Compose
Orientierung an deinem bestehenden [docker-compose.yml](docker-compose.yml):
- `postgres` mit `healthcheck`
- `cms` `depends_on: postgres: service_healthy`
- `web` `depends_on: cms` + `DATABASE_URL` nur wenn Web eigene DB braucht (meist nicht nur CMS nutzt DB)
Entrypoint-Pattern von [docker/entrypoint.sh](docker/entrypoint.sh) übernehmen: **DB warten → Migration → dann Prozess starten**.
---
## Coolify-Workflow (End-to-End)
```mermaid
sequenceDiagram
participant Dev as Developer
participant GH as GitHub
participant GHA as GitHub Actions
participant CF as Coolify
participant Web as Next Container
participant CMS as Payload Container
Dev->>GH: push feature branch
Dev->>GH: open PR
GHA->>GHA: lint typecheck build docker
GHA-->>Dev: PR checks green
Dev->>GH: merge to main
GH->>CF: webhook deploy
CF->>CF: build CMS image
CF->>CF: build Web image
CF->>Web: rolling update
CMS->>Web: optional revalidate webhook
```
**Coolify-Konfiguration pro App:**
| Setting | Web | CMS |
|---------|-----|-----|
| Build Pack | Dockerfile | Dockerfile |
| Branch | `main` | `main` |
| Port | 3000 | 3001 |
| Health | `/api/health` | `/api/health` oder Payload-Default |
| Secrets | `REVALIDATE_SECRET`, `CMS_URL` | `DATABASE_URL`, `PAYLOAD_SECRET` |
**Checkliste Erstdeploy** (aus [docs/COOLIFY.md](docs/COOLIFY.md) übertragbar):
1. Postgres healthy, internal URL notieren
2. CMS deployen, Admin anlegen, Collections seeden
3. Web deployen mit internal `CMS_URL`
4. Domain + HTTPS (Traefik)
5. Webhook Payload → Next Revalidate testen
6. `RUN_DB_SEED` / Migration-Flags wieder aus
---
## GitHub Actions (CI vor Coolify)
**Workflow `ci.yml`** (bei jedem PR + push auf `main`):
1. **checkout**
2. **Node 22** + Cache (`apps/web`, `apps/cms`)
3. **Parallel jobs oder Matrix:**
- `npm run lint` (ESLint)
- `npm run typecheck` (`tsc --noEmit`)
- `npm run build` (Web + CMS)
4. **Docker build test** (ohne Push):
- `docker build -f apps/web/Dockerfile apps/web`
- `docker build -f apps/cms/Dockerfile apps/cms`
5. **(optional) Playwright** gegen `docker compose up` Smoke: Startseite, eine CMS-Seite, Health endpoints
6. **(optional) PR Review** bestehendes Gemini-Workflow aus FlixCooks wiederverwenden
**Branch-Schutz:** `main` nur mit grünen Required Checks mergebar.
Coolify deployt **nach** Merge CI blockiert kaputte Images, Coolify baut das echte Production-Image (oder du pushst zu GHCR für den Start reicht Coolify-eigener Build).
---
## KI-gestützte Entwicklung mit MCP
**Cursor `mcp.json` (Team-Standard):**
| MCP | Zweck |
|-----|--------|
| **GitHub** | Issues, PRs, Actions-Logs aus dem Chat |
| **Context7** (oder Fetch) | Aktuelle Next.js / Payload / GSAP-Docs |
| **Postgres** (optional, nur Dev) | Content/Debugging nie Production-Credentials im Repo |
| **Filesystem** | Standard in Cursor |
**Projekt-Wissen für Agenten** (aus FlixCooks übernehmen):
- [.agents/brain.md](.agents/brain.md) Architektur, Env-Regeln, Coolify-Hosts
- [.agents/rules/AGENT.md](.agents/rules/AGENT.md) Commit/PR/TODO-Konventionen
- `docs/COOLIFY.md` Deploy-Runbook pro Projekt
**Typischer KI-Workflow:**
1. Ticket/Issue in GitHub (MCP)
2. Feature-Branch; Agent ändert `apps/web` + Payload-Collection
3. `docker compose up` lokal; Agent nutzt Health-URLs
4. PR → CI grün → Gemini-Review optional
5. Merge → Coolify
---
## Entwickler-Alltag (Kurzablauf)
1. `cp .env.example .env` lokale URLs
2. `docker compose -f docker-compose.dev.yml up -d` (nur Postgres) **oder** volles `docker compose up`
3. `npm run dev` in `apps/web` und `apps/cms` (schneller Hot Reload) **oder** alles in Containern
4. In Payload Inhalte pflegen → Webhook triggert Revalidate
5. `git push` → PR → CI → merge → Coolify rebuild
---
## Bezug zu FlixCooks (dieses Repo)
FlixCooks ist heute **Vanilla PHP + Postgres + eingebautes `admin.php`-CMS** kein React. Das ist ein **paralleler Stack**, kein Widerspruch:
| Aspekt | FlixCooks (aktuell) | Neuer React-Stack |
|--------|---------------------|-------------------|
| Frontend | PHP-Templates | Next.js + React |
| CMS | `admin.php` | Payload (Container) |
| DB | Postgres | Postgres |
| Deploy | [Dockerfile](Dockerfile) + [COOLIFY.md](docs/COOLIFY.md) | gleiches Muster, zwei App-Services |
| Animationen | Lenis, Vanilla CSS | Lenis + GSAP + Framer |
Du kannst FlixCooks auf Coolify weiterbetreiben und **neue Projekte** im Monorepo-Template starten. Eine spätere Migration FlixCooks → Next wäre ein separates Projekt (Content-Export aus Postgres/JSON → Payload-Collections).
---
## Nächste konkrete Schritte (nach Plan-Freigabe)
1. **Greenfield-Repo** aus der Struktur oben scaffolden (oder `create-payload-app` + Next in Monorepo).
2. **Minimale Collections** in Payload: `pages`, `recipes` (oder `projects`), `siteSettings`, Media.
3. **Dockerfiles + compose** + `docs/COOLIFY.md` vom FlixCooks-Muster kopieren/adaptieren.
4. **GitHub Actions `ci.yml`** anlegen.
5. **Coolify:** Postgres → CMS → Web → Webhook Revalidate testen.
6. **`.cursor/mcp.json` + `.agents/brain.md`** für das neue Repo.
Wenn du willst, kann im nächsten Schritt ein **konkretes Starter-Repo** (Dateien + minimale Hero-Animation + eine Payload-Collection) direkt in einem neuen Ordner oder Branch angelegt werden.
+12
View File
@@ -0,0 +1,12 @@
.git
.github
.agents
.env
.env.*
!.env.example
docker-compose.dev.yml
docker-compose.yml
terminals
*.md
!README.md
.cursor
+6 -1
View File
@@ -2,5 +2,10 @@
# Kopieren: cp .env.example .env # Kopieren: cp .env.example .env
# --- Postgres (Pflicht für die Website) --- # --- Postgres (Pflicht für die Website) ---
# docker compose -f docker-compose.dev.yml up -d # Lokal: docker compose -f docker-compose.dev.yml up -d
DATABASE_URL="postgresql://flixcooks:flixcooks_dev@127.0.0.1:5432/flixcooks_dev" DATABASE_URL="postgresql://flixcooks:flixcooks_dev@127.0.0.1:5432/flixcooks_dev"
# --- Production / Coolify (im Dashboard setzen, nicht committen) ---
# DATABASE_URL="postgresql://user:pass@postgresql-service:5432/flixcooks"
# FLIXCOOKS_ADMIN_KEY="langes-zufaelliges-passwort"
# RUN_DB_SEED="true" # nur beim allerersten Deploy, danach entfernen
+2 -2
View File
@@ -1,2 +1,2 @@
# Auto detect text files and perform LF normalization * text=auto eol=lf
* text=auto *.sh text eol=lf
+37
View File
@@ -0,0 +1,37 @@
# FlixCooks Production image (Coolify / any Docker host)
FROM php:8.3-apache-bookworm
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq-dev \
&& docker-php-ext-install pdo_pgsql \
&& a2enmod rewrite headers \
&& rm -rf /var/lib/apt/lists/*
# Apache: document root + AllowOverride for .htaccess
ENV APACHE_DOCUMENT_ROOT=/var/www/html
RUN sed -ri 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \
&& sed -ri 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf \
&& printf '%s\n' \
'<Directory /var/www/html>' \
' AllowOverride All' \
' Require all granted' \
'</Directory>' \
> /etc/apache2/conf-available/flixcooks.conf \
&& a2enconf flixcooks
WORKDIR /var/www/html
COPY --chown=www-data:www-data . /var/www/html
RUN sed -i 's/\r$//' /var/www/html/docker/entrypoint.sh \
&& chmod +x /var/www/html/docker/entrypoint.sh \
&& mkdir -p /var/www/html/data \
&& chown -R www-data:www-data /var/www/html/data
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
CMD php /var/www/html/health.php >/dev/null || exit 1
ENTRYPOINT ["/var/www/html/docker/entrypoint.sh"]
CMD ["apache2-foreground"]
+8
View File
@@ -159,6 +159,14 @@ Schema: `scripts/schema.sql`. PHP baut daraus dieselben Arrays wie früher (`i18
Für **Staging/Production** nur `DATABASE_URL` in der Hosting-Umgebung setzen nie Production-Daten in der lokalen Dev-DB mischen. Für **Staging/Production** nur `DATABASE_URL` in der Hosting-Umgebung setzen nie Production-Daten in der lokalen Dev-DB mischen.
### Docker / Coolify
Production-Image: `Dockerfile` im Repo-Root. Ausführliche Schritte: [docs/COOLIFY.md](docs/COOLIFY.md).
```bash
docker compose build && docker compose up -d # lokal testen → http://127.0.0.1:8080
```
--- ---
## 📈 Development Tracking & Progress ## 📈 Development Tracking & Progress
+42
View File
@@ -0,0 +1,42 @@
# Lokaler Produktions-Test: App-Image + Postgres (ähnlich Coolify mit zwei Services)
#
# docker compose build
# docker compose up -d
# curl http://127.0.0.1:8080/health.php
#
# Erstes Deployment mit Seed:
# RUN_DB_SEED=true docker compose up -d
services:
web:
build: .
ports:
- "8080:80"
environment:
DATABASE_URL: postgresql://flixcooks:flixcooks_prod@postgres:5432/flixcooks
FLIXCOOKS_ADMIN_KEY: ${FLIXCOOKS_ADMIN_KEY:-change-me-in-production}
github-actions[bot] commented 2026-05-23 21:30:28 +00:00 (Migrated from github.com)
Review

The default value change-me-in-production is a good security practice for development environments. However, ensure that this variable is always overridden in production environments. Consider adding a validation check or a more prominent warning if this default value is detected in a production context, perhaps during the application's startup.

The default value `change-me-in-production` is a good security practice for development environments. However, ensure that this variable is *always* overridden in production environments. Consider adding a validation check or a more prominent warning if this default value is detected in a production context, perhaps during the application's startup.
RUN_DB_SEED: ${RUN_DB_SEED:-false}
depends_on:
postgres:
condition: service_healthy
github-actions[bot] commented 2026-05-23 21:30:28 +00:00 (Migrated from github.com)
Review

This is good practice for ensuring the database is ready before the application starts. However, the healthcheck in the postgres service has interval: 5s and timeout: 5s. If the database takes slightly longer to become fully ready than these parameters allow, the web service might still fail to start. Consider increasing the interval or timeout slightly, or ensuring the pg_isready command is robust enough to handle initial startup states.

This is good practice for ensuring the database is ready before the application starts. However, the `healthcheck` in the `postgres` service has `interval: 5s` and `timeout: 5s`. If the database takes slightly longer to become fully ready than these parameters allow, the `web` service might still fail to start. Consider increasing the `interval` or `timeout` slightly, or ensuring the `pg_isready` command is robust enough to handle initial startup states.
volumes:
# Impressum/Datenschutz-Einstellungen persistent halten
- site_data:/var/www/html/data
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: flixcooks
POSTGRES_PASSWORD: flixcooks_prod
POSTGRES_DB: flixcooks
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U flixcooks -d flixcooks"]
interval: 5s
timeout: 5s
retries: 10
volumes:
pg_data:
site_data:
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash
github-actions[bot] commented 2026-05-23 21:30:28 +00:00 (Migrated from github.com)
Review

It's good practice to include set -euo pipefail in shell scripts to make them more robust by exiting on unbound variables (-u), non-zero exit codes (-e), and pipeline failures (-o pipefail). This is already present, which is excellent.

It's good practice to include `set -euo pipefail` in shell scripts to make them more robust by exiting on unbound variables (`-u`), non-zero exit codes (`-e`), and pipeline failures (`-o pipefail`). This is already present, which is excellent.
set -euo pipefail
cd /var/www/html
echo "[flixcooks] Waiting for database..."
TRIES=0
MAX_TRIES="${DB_WAIT_MAX_TRIES:-30}"
github-actions[bot] commented 2026-05-23 21:30:28 +00:00 (Migrated from github.com)
Review

Making the maximum number of retries configurable via an environment variable is a good flexible design. The default of 30 attempts (with a 2-second sleep) provides a generous 60-second wait, which is generally sufficient. Ensure this timeout is documented or understood by users deploying the application.

Making the maximum number of retries configurable via an environment variable is a good flexible design. The default of 30 attempts (with a 2-second sleep) provides a generous 60-second wait, which is generally sufficient. Ensure this timeout is documented or understood by users deploying the application.
until php scripts/db-check.php >/dev/null 2>&1; do
TRIES=$((TRIES + 1))
if [ "$TRIES" -ge "$MAX_TRIES" ]; then
echo "[flixcooks] Database not reachable after ${MAX_TRIES} attempts." >&2
exit 1
fi
sleep 2
done
echo "[flixcooks] Applying schema..."
php -r "require 'helpers.php'; require_database(); echo \"schema ok\n\";"
if [ "${RUN_DB_SEED:-false}" = "true" ]; then
echo "[flixcooks] Seeding recipes from data/recipes.json..."
php scripts/db-seed.php
fi
echo "[flixcooks] Starting Apache..."
exec "$@"
+140
View File
@@ -0,0 +1,140 @@
# FlixCooks auf Coolify deployen
Zwei getrennte Ressourcen: **PostgreSQL** und **PHP-Web-App** (dieses Repo als Dockerfile).
## Architektur
```
┌──────────────────── Coolify Server ────────────────────┐
│ │
│ ┌──────────────┐ ┌─────────────────────────┐ │
│ │ PostgreSQL │◄────────│ FlixCooks (dieses Image) │ │
│ │ (Service B) │ :5432 │ Apache + PHP 8.3 │ │
│ └──────────────┘ │ Port 80 → Traefik/HTTPS │ │
│ ▲ └─────────────────────────┘ │
│ │ ▲ │
│ Volume (Daten) Volume optional: │
│ data/ (site.json) │
└─────────────────────────────────────────────────────────┘
```
Die App startet **nicht**, wenn `DATABASE_URL` fehlt oder Postgres nicht erreichbar ist.
---
## 1. PostgreSQL in Coolify anlegen
1. Neues **Database** → PostgreSQL (16).
2. Notieren:
- Benutzer, Passwort, Datenbankname
- **Internal URL** (Host ist oft der Service-Name, z.B. `postgresql-xxxxx` oder was Coolify anzeigt)
3. Format für die App:
```text
postgresql://USER:PASSWORD@HOST:5432/DATABASE
```
Beispiel (Platzhalter durch Coolify-Werte ersetzen):
```text
postgresql://flixcooks:geheim@postgresql-flixcooks:5432/flixcooks
```
**Wichtig:** In der App den **internen** Hostnamen verwenden (gleiches Coolify-Netzwerk), nicht `127.0.0.1`.
---
## 2. Web-App in Coolify anlegen
1. Neues **Application** → Build Pack: **Dockerfile** (Repository dieses Projekts).
2. Dockerfile-Pfad: `Dockerfile` (Root).
3. Port: **80** (Container exponiert Apache auf 80).
4. Health Check (optional, empfohlen):
- Path: `/health.php`
- Erwartet HTTP 200 mit `{"status":"ok"}`
### Environment Variables (Pflicht)
| Variable | Beschreibung |
|----------|----------------|
| `DATABASE_URL` | Interne Postgres-URL von Coolify |
| `FLIXCOOKS_ADMIN_KEY` | Starkes Passwort für `/admin.php` |
### Environment Variables (optional)
| Variable | Default | Beschreibung |
|----------|---------|----------------|
| `RUN_DB_SEED` | `false` | Einmalig `true` setzen → importiert `data/recipes.json` beim Start |
| `DB_WAIT_MAX_TRIES` | `30` | Warteversuche bis Postgres da ist (à 2 s) |
Nach dem ersten erfolgreichen Deploy: `RUN_DB_SEED` wieder auf `false` oder entfernen.
### Persistent Storage (empfohlen)
Mount für Impressum/Datenschutz (`data/site.json`):
| Mount Path (Container) | Inhalt |
|------------------------|--------|
| `/var/www/html/data` | `site.json` bleibt nach Redeploy erhalten |
Rezepte liegen in Postgres **kein** Volume für Rezepte nötig.
---
## 3. Erstes Deployment (Checkliste)
1. Postgres-Service läuft (healthy).
2. App mit `DATABASE_URL` + `FLIXCOOKS_ADMIN_KEY` deployen.
3. Einmalig `RUN_DB_SEED=true` → Redeploy → Rezepte prüfen auf der Startseite.
4. `RUN_DB_SEED` deaktivieren.
5. `https://deine-domain/admin.php` testen.
6. `https://deine-domain/health.php``{"status":"ok"}`.
### Schema ohne Seed
Tabellen legt der Container beim Start automatisch an (`scripts/schema.sql` via `require_database()`). Ohne Seed ist die DB leer → Seite lädt, aber keine Rezepte, bis du im Admin anlegst oder seedest.
---
## 4. Lokaler Test vor Coolify
```bash
# Starkes Admin-Passwort setzen
export FLIXCOOKS_ADMIN_KEY="dein-geheimes-passwort"
# Mit Seed
export RUN_DB_SEED=true
docker compose build
docker compose up -d
curl http://127.0.0.1:8080/health.php
```
---
## 5. Updates / Redeploy
- Neues Image bauen lassen (Git push → Coolify rebuild).
- Postgres-Volume bleibt → Daten bleiben.
- `data/`-Volume bleibt → Site-Settings bleiben.
- Kein manuelles `db-seed` bei Updates, außer du leerst die DB bewusst.
---
## 6. Sicherheit
- `.env` wird **nicht** ins Image kopiert (`.dockerignore`).
- Admin-Key **nur** über `FLIXCOOKS_ADMIN_KEY` in Coolify, nicht in `.htaccess` für Production verlassen.
- Postgres nicht öffentlich exponieren, wenn nicht nötig (nur interne URL).
---
## 7. Troubleshooting
| Problem | Lösung |
|---------|--------|
| Container startet nicht | Logs: DB nicht erreichbar → `DATABASE_URL` Host/Passwort prüfen |
| 503 „Datenbank nicht verfügbar“ | Gleiches Netzwerk in Coolify? Internal URL? |
| Leere Seite, Health OK | `RUN_DB_SEED=true` einmalig oder Admin-Rezepte anlegen |
| Admin geht nicht | `FLIXCOOKS_ADMIN_KEY` gesetzt? |
| `site.json` verloren nach Deploy | Volume auf `/var/www/html/data` mounten |
+25
View File
@@ -0,0 +1,25 @@
<?php
/**
* Container health check (Coolify / Docker HEALTHCHECK).
*/
header('Content-Type: application/json; charset=utf-8');
require __DIR__ . '/config.php';
try {
github-actions[bot] commented 2026-05-23 21:30:29 +00:00 (Migrated from github.com)
Review

Wrapping the load_recipes() call in a try...catch block is essential for handling potential DatabaseUnavailableException errors gracefully, especially on pages that are not intended to show a maintenance page.

Wrapping the `load_recipes()` call in a `try...catch` block is essential for handling potential `DatabaseUnavailableException` errors gracefully, especially on pages that are not intended to show a maintenance page.
if (!extension_loaded('pdo_pgsql')) {
throw new RuntimeException('pdo_pgsql extension missing');
}
require_once __DIR__ . '/helpers.php';
require_database();
$response = ['status' => 'ok'];
echo json_encode($response, JSON_UNESCAPED_UNICODE);
} catch (Throwable $e) {
http_response_code(503);
$response = [
'status' => 'error',
'message' => $e->getMessage(),
];
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit(1);
}