39 lines
1.9 KiB
Markdown
39 lines
1.9 KiB
Markdown
# Statische, datengetriebene Website mit PDF-Download je Eintrag (2026-08-08)
|
|
|
|
Muster für eine statische Status-/Listen-Seite auf einer Subdomain, die aus einem
|
|
JSON-Datensatz rendert und **pro Eintrag ein PDF** zum Download anbietet
|
|
(wkhtmltopdf, kein PHP/Python-Backend nötig). Beispiel: Zugverbindungs-Liste mit
|
|
je-Ziel-PDF (urlaub.perfekt-ohne-en.de).
|
|
|
|
## Bausteine
|
|
|
|
1. **Datenquelle**: eine `daten.json` im Webroot (Liste von Objekten mit den
|
|
anzuzeigenden Feldern + Fahrtzeit + Kategorie + Weg).
|
|
2. **`index.html`**: lädt `daten.json` per `fetch`, gruppiert nach Kategorie
|
|
(z.B. Kernziel / über-7h / Fernzone) und rendert Tabellen mit
|
|
`<a href="pdf/<slug>.pdf">⬇ PDF</a>`-Buttons.
|
|
Slug-Funktion: lowercase + NFD-normalisieren + Umlaute streifen + `[^a-z0-9]`→`-`.
|
|
3. **PDF-Generator** (`/usr/local/bin/<projekt>-pdf.sh`):
|
|
- Python-Schleife: liest `daten.json`, baut je Eintrag eine temporäre HTML-Datei
|
|
in `/tmp/<projekt>-html/`, schreibt nach `/var/www/<sub>/pdf/<slug>.pdf`.
|
|
- `wkhtmltopdf --quiet --enable-local-file-access "$html" "$pdf"`.
|
|
- Danach `chown -R www-data:www-data <webroot>` (write_file erzeugt root:root).
|
|
- Glob-Sicherheit bei leeren Verzeichnissen: `rm -rf /tmp/.../*` vorher oder
|
|
`shopt -s nullglob` (vgl. `set -euo pipefail`).
|
|
|
|
## Pitfalls
|
|
|
|
- **`write_file` weigert sich auf `/etc/nginx/...`** (sensitiver Systempfad).
|
|
Ersatz: Inhalt nach `/tmp/<datei>` schreiben, dann `cp /tmp/<datei> /etc/nginx/...`.
|
|
- **PDF nicht roh per `grep` prüfbar**: wkhtmltopdf komprimiert den Text. Statt
|
|
Text-Suche lieber (a) Größe (KB) + valides `%%EOF`-Ende prüfen, oder
|
|
(b) PDF im Browser öffnen (Browserbase rendert es im PDF-Viewer) als visueller Beweis.
|
|
|
|
## Verifikation (end-to-end)
|
|
|
|
```bash
|
|
for f in /var/www/<sub>/pdf/*.pdf; do
|
|
curl -sk -o /dev/null -w "%{http_code}\n" "https://<sub>.perfekt-ohne-en.de/pdf/$(basename "$f")"
|
|
done
|
|
# Alle 200 => PDFs OK. Zusätztlich index.html + daten.json auf 200 prüfen.
|
|
``` |