Files
Per Hoener 0d45331f5c
Deploy / validate-dispatch (push) Successful in 43s
Deploy / scheduled-rebuild-dev (push) Skipped
Deploy / scheduled-rebuild-master (push) Skipped
Deploy / rollback-dev (push) Skipped
Deploy / rollback-master (push) Skipped
Deploy / changes (push) Successful in 13s
Deploy / secret-scan (push) Successful in 9s
Deploy / app-quality (push) Successful in 11m21s
Deploy / security-deps (push) Successful in 14s
Deploy / context (push) Failing after 1s
Deploy / app-image (push) Skipped
Deploy / deploy-dev (push) Skipped
Deploy / deploy-master (push) Skipped
Initial commit
2026-09-18 23:37:19 +02:00

144 lines
7.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Next.js Website Starter
Neutrale, wiederverwendbare technische Basis für eine neue Website. Das Repository enthält eine produktionsfähige Next.js-Anwendung mit Kalender-API, Bildpipeline, Tests, Containerisierung sowie CI/CD, aber bewusst keine fachlichen Inhalte oder produktiven Daten.
## Technologie-Stack
- Node.js 24 und npm
- Next.js 16 App Router mit React 19 und TypeScript
- Standalone-Serverausgabe für Docker
- ICS-Kalender mit `ical.js`, `rrule` und Temporal
- Zod für Runtime-Konfiguration
- Vitest sowie ein produktionsnaher E2E-Smoke-Test
- ESLint, Husky und lint-staged
- Sharp für responsive Bildvarianten und Metadatenbereinigung
- Docker Compose, Traefik und Trivy
- Gitea-Actions-kompatible Workflows unter `.gitea/workflows/`
Eine Datenbank und eine Authentifizierung sind nicht Bestandteil dieser Vorlage, weil das technische Ausgangsprojekt keine solchen Systeme verwendet.
## Struktur
- `src/app/`: Seiten, Metadaten-, API- und Health-Routen
- `src/components/`: wiederverwendbare Server- und Client-Komponenten
- `src/server/calendar/`: ICS-Abruf, Parser, Cache, Fehlerbehandlung und Readiness
- `src/trip-reports/`: registrierbare TSX-Beitragsmodule; im Starter leer
- `src/data/`: neutrale Datenregistries für Downloads, Galerien und Inhaltskarten
- `.media-source/`: Originalbilder für die Bildpipeline
- `public/`: generierte Bilder, lokale Schriften und öffentliche Dateien
- `scripts/`: Build-, Medien-, E2E-, Security- und Deploy-Hilfen
- `.gitea/workflows/`: CI, Deployment, Rollback und geplante Rebuilds
Die vorhandenen deutschsprachigen Routen bleiben aus Kompatibilitätsgründen erhalten: `/`, `/ueber-uns`, `/informationen`, `/kalender`, `/fahrten`, `/fahrten/[slug]`, `/bilder`, `/impressum` und `/datenschutz`.
## Lokale Installation
Voraussetzungen sind Node.js gemäß `.node-version`, npm und für Container-Workflows Docker.
```bash
npm ci
cp .env.example .env.local
npm run dev
```
Die Anwendung ist anschließend standardmäßig unter `http://localhost:3000` erreichbar. Für echte Kalenderdaten muss `CALENDAR_URL` auf eine erreichbare HTTPS-ICS-Datei zeigen.
## Environment-Variablen
Alle Werte in `.env.example` sind ungefährliche Beispiele.
| Variable | Zweck |
| --- | --- |
| `APP_NAME` | Öffentlicher Name der Website |
| `APP_URL` | Kanonische Basis-URL für SEO, Sitemap, Hostprüfung und CORS-Default |
| `COMPANY_NAME` | Betreiber-/Organisationsname |
| `CONTACT_EMAIL` | Öffentliche Kontaktadresse |
| `CONTACT_PHONE` | Öffentliche Telefonnummer |
| `CONTACT_ADDRESS` | Öffentliche Anschrift |
| `PRIMARY_DOMAIN` | Hostname für Traefik |
| `CALENDAR_URL` | HTTPS-URL des ICS-Kalenders; zur Laufzeit erforderlich |
| `CORS_ORIGIN` | Kommagetrennte erlaubte Origins; Standard ist `APP_URL` |
| `TRUSTED_PROXIES` | JSON-Liste oder CSV vertrauenswürdiger Proxy-Netze |
| `CALENDAR_CACHE_DURATION_MS` | Cache-Dauer für Kalenderdaten |
| `CALENDAR_FETCH_TIMEOUT_MS` | Timeout für den ICS-Abruf |
| `DEFAULT_CALENDAR_TIMEZONE` | IANA-Zeitzone für schwebende ICS-Zeitangaben |
| `MAX_RECURRENCE_WINDOW_MONTHS` | Maximales Vorschaufenster wiederkehrender Termine |
| `MAX_ICS_BYTES` | Maximale Größe der Kalenderdatei |
| `MAX_OCCURRENCES_PER_EVENT` | Obergrenze je wiederkehrendem Termin |
| `ROUTINE_EVENT_TITLES` | Titel regulärer Termine, die nicht hervorgehoben werden |
`CALENDAR_URL` ist ein Runtime-Secret und wird nicht als Docker-Build-Argument verwendet. Öffentliche Identitätswerte werden beim Container-Build gesetzt, da Next.js Metadaten statisch erzeugen kann, und zusätzlich zur Laufzeit an den Container übergeben.
## Befehle
```bash
npm run dev
npm run lint
npm run typecheck
npm run test
npm run build
npm run test:e2e
```
`npm run build` bereinigt öffentliche Dateien, erzeugt beziehungsweise entfernt Bildvarianten, entfernt Bildmetadaten, prüft PDF-Metadaten und führt `next build` aus. Der E2E-Test baut die Standalone-Ausgabe, startet eine lokale ICS-Fixture und prüft Seiten, API, ETag sowie Health-Routen.
Mit `npm run content:new` kann ein neues TSX-Beitragsmodul samt optionalen Originalbildern angelegt werden.
## Bilder und Dateien
Originalbilder gehören in die Unterverzeichnisse von `.media-source/`. `npm run images` erzeugt responsive JPEG-, WebP- und AVIF-Varianten in `public/images/`; `npm run images:prune` entfernt Varianten ohne Quelle. Neue Alt-Texte werden projektspezifisch in der Medienkonfiguration oder im erzeugten Manifest gepflegt.
Downloads werden in `public/downloads/` abgelegt und in `src/data/downloads.ts` registriert. Keine personenbezogenen, produktiven oder vertraulichen Dateien committen.
## Docker
Für einen lokalen Start über den vorhandenen Traefik-Stack:
```bash
CALENDAR_URL=https://example.com/calendar.ics docker compose up --build
```
Das externe Netzwerk heißt standardmäßig `traefik-external` und kann mit `TRAEFIK_NETWORK_NAME` geändert werden. Für einen isolierten Test ohne vorhandenes Traefik-Netz kann die Compose-Datei projektspezifisch überschrieben werden.
Das Runtime-Image läuft ohne Root-Rechte, mit read-only Dateisystem, entfernten Linux-Capabilities, Healthcheck und Ressourcenlimits.
## CI/CD und Deployment
Die Workflows bleiben vollständig erhalten:
- `.gitea/workflows/ci.yml` führt Lint, Tests, Typecheck, Build, E2E sowie Secret- und Schwachstellenscans aus.
- `.gitea/workflows/deploy.yml` baut und scannt Images, deployt `dev` und `master`, prüft die laufende Anwendung, unterstützt Rollbacks und führt wöchentliche Rebuilds aus aktuellen Basis-Images aus.
CI ist für den lokalen Start nicht technisch erforderlich. Für gemeinsame Branches und Deployments sollte sie aktiv bleiben, weil sie reproduzierbar Build, Tests, Secret-Scans und Container prüft. Auf einem warmen Runner ist für die reine App-Prüfung typischerweise mit etwa 25 Minuten zu rechnen; ein kalter Runner mit LFS-, Container- und Trivy-Downloads kann etwa 515 Minuten benötigen. Die Security-Jobs laufen parallel. Die tatsächliche Dauer hängt von Runner, Cache, Medienumfang und Netzwerk ab; die Job-Timeouts liegen je nach Aufgabe bei 545 Minuten.
Vor dem ersten Deployment sind mindestens folgende Repository-Variablen zu setzen:
- `CI_RUNNER`, optional `PROD_RUNNER`
- `CONTAINER_REGISTRY`
- `APP_IMAGE_REPOSITORY`
- `APP_NAME`, `COMPANY_NAME`, `CONTACT_EMAIL`, `CONTACT_PHONE`, `CONTACT_ADDRESS`
- `DEV_PRIMARY_DOMAIN`, `PROD_PRIMARY_DOMAIN`
- optional `DEV_APP_URL`, `PROD_APP_URL`, `DEV_CORS_ORIGIN`, `PROD_CORS_ORIGIN`
- optional Stack- und Netzwerkwerte `*_DEPLOY_STACK_NAME`, `*_TRAEFIK_NETWORK_NAME`
Benötigte Secrets:
- `CALENDAR_URL`
- `PACKAGES_USERNAME`, `PACKAGES_TOKEN`
- `DEV_TRAEFIK_CERTRESOLVER`, `PROD_TRAEFIK_CERTRESOLVER`
Runner benötigen Docker, Zugriff auf das Zielnetzwerk und bei produktiven Deployments Zugriff auf den Zielhost.
## Für ein neues Projekt anpassen
1. Alle Werte aus `.env.example` für die neue Installation festlegen.
2. Texte und Navigation in `src/app/` und `src/components/Header.tsx` ersetzen.
3. Rechtstexte fachlich und rechtlich erstellen lassen.
4. Neues Logo, Farbschema, Schriften und Medien einpflegen.
5. Kalenderquelle und Titel regulärer Termine konfigurieren.
6. Beitrags-, Download- und Galerie-Registries befüllen.
7. Registry, Runner, Domains, Traefik und Secrets in CI/CD konfigurieren.
8. Alle Qualitätsprüfungen und den finalen Secret-Scan ausführen.
Die Beispielwerte sind nicht für eine produktive Veröffentlichung bestimmt.