Update .env.example for local and production database configurations, ensuring clarity on usage. Modify .gitattributes to enforce LF line endings for shell scripts. Enhance README.md with Docker and Coolify setup instructions for production deployment.
This commit is contained in:
@@ -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 33–43)
|
||||
- `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.
|
||||
@@ -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
@@ -2,5 +2,10 @@
|
||||
# Kopieren: cp .env.example .env
|
||||
|
||||
# --- 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"
|
||||
|
||||
# --- 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
@@ -1,2 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
* text=auto eol=lf
|
||||
*.sh text eol=lf
|
||||
|
||||
+37
@@ -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"]
|
||||
@@ -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.
|
||||
|
||||
### 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
|
||||
|
||||
@@ -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}
|
||||
RUN_DB_SEED: ${RUN_DB_SEED:-false}
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
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:
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
echo "[flixcooks] Waiting for database..."
|
||||
TRIES=0
|
||||
MAX_TRIES="${DB_WAIT_MAX_TRIES:-30}"
|
||||
|
||||
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
@@ -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
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* Container health check (Coolify / Docker HEALTHCHECK).
|
||||
*/
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require __DIR__ . '/config.php';
|
||||
|
||||
try {
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user