diff --git a/.cursor/plans/coolify_react_cms_stack_ea69bc7d.plan.md b/.cursor/plans/coolify_react_cms_stack_ea69bc7d.plan.md new file mode 100644 index 0000000..e0d7bc5 --- /dev/null +++ b/.cursor/plans/coolify_react_cms_stack_ea69bc7d.plan.md @@ -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. diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..88018b8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +.git +.github +.agents +.env +.env.* +!.env.example +docker-compose.dev.yml +docker-compose.yml +terminals +*.md +!README.md +.cursor diff --git a/.env.example b/.env.example index 744a47b..8ec31d8 100644 --- a/.env.example +++ b/.env.example @@ -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 diff --git a/.gitattributes b/.gitattributes index dfe0770..f7e2def 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ -# Auto detect text files and perform LF normalization -* text=auto +* text=auto eol=lf +*.sh text eol=lf diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2b55a59 --- /dev/null +++ b/Dockerfile @@ -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' \ + '' \ + ' AllowOverride All' \ + ' Require all granted' \ + '' \ + > /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"] diff --git a/README.md b/README.md index 291170f..7f13002 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5ec26a7 --- /dev/null +++ b/docker-compose.yml @@ -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: diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..c5db388 --- /dev/null +++ b/docker/entrypoint.sh @@ -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 "$@" diff --git a/docs/COOLIFY.md b/docs/COOLIFY.md new file mode 100644 index 0000000..5545c3d --- /dev/null +++ b/docs/COOLIFY.md @@ -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 | diff --git a/health.php b/health.php new file mode 100644 index 0000000..f3d269b --- /dev/null +++ b/health.php @@ -0,0 +1,25 @@ + '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); +}