# Autoren-Portfolio-Suite Eine selbst gehostete Portfolio-Anwendung für mehrere voneinander getrennte Autorenprofile. Inhalte, Bücher, laufende Projekte, Designs, SEO-Daten und Rechtstexte werden über eine gemeinsame, passwortgeschützte Administrationsoberfläche gepflegt. Technisch besteht die Anwendung aus einem React-/Tailwind-Frontend und einem Express-Backend. Sie kann als einzelner Docker-Container betrieben werden und benötigt keine externe Datenbank. ## Funktionsumfang - Mehrere unabhängig konfigurierte Autorenprofile mit eigenen Domains und Themes - Biografie, Schlagworte, individuelle Texte und optionale Zusatzsektion mit bis zu drei CTA-Buttons - Bücherregal mit Detailansicht, Cover, Kauflink und optionaler Spotify-Playlist - Aktuelle Projekte mit Fortschritt, Markdown-Detailtext, Bild und optionaler Spotify-Playlist - Lokaler Bild-Upload über den Adminbereich - Verwaltung von Impressum, Datenschutzerklärung und weiteren Rechtstexten - Optionale serverseitige Gemini-Unterstützung für Klappentexte - Profilabhängige SEO-Metadaten, Open Graph, strukturierte Daten, Sitemap und `robots.txt` - Health-Endpunkte, persistente JSON-Datenhaltung und automatische Migrationsbackups ## Trennung der Profile Die öffentliche Seite erhält ausschließlich die Daten des Profils, das zur aufgerufenen Domain gehört. Andere Profile, deren Domains und interne Pfadkonfigurationen werden von der öffentlichen API nicht ausgeliefert. Im Produktionsmodus gilt der Hostname als Trennlinie: - Konfigurierte Domains reagieren nur auf die exakte Domain und deren `www`-Variante. - Ein URL-Pfad oder Query-Parameter kann nicht zu einem anderen Profil wechseln. - Pfadbasierte Profilvorschauen stehen nur in der lokalen Entwicklungsumgebung zur Verfügung. - Vollständige Profildaten sind ausschließlich über einen authentifizierten Admin-Endpunkt verfügbar. - Gemeinsam gepflegte Rechtstexte werden bei der öffentlichen Ausgabe von strukturiert bekannten Kennungen anderer Profile bereinigt. Die gespeicherten Originaltexte bleiben unverändert. - Querverlinkungen entstehen nur durch ausdrücklich gepflegte Buttons oder Inhalte des jeweiligen Profils; es gibt keine automatische Verbindung zu anderen Profilen. Der Reverse Proxy sollte zusätzlich nur die tatsächlich verwendeten Domains an den Container weiterleiten. ## Architektur Die öffentlichen Portfolioseiten verwenden eine gemeinsame, daten- und themegesteuerte React-Komponente. Dadurch liegen Layout, Buch- und Projektmodale, Rechtstexte sowie die Medienintegration nur einmal im Code vor. Profilbezogene Inhalte und Farben kommen aus der Datenbank; die Auswahl des Profils findet serverseitig statt. Wichtige Verzeichnisse und Dateien: ```text src/App.tsx Öffentliche/Admin-Routen und Datenabruf src/components/PortfolioPage.tsx Gemeinsame öffentliche Portfolioseite src/components/AdminPanel.tsx Administrationsarbeitsbereich src/components/admin/ Ausgelagerte Admin-Komponenten src/defaultData.ts Ausgangsdaten für eine neue Installation server.ts API, Routing, Sessions, Uploads und SEO data/database.json Persistente Inhaltsdaten data/uploads/ Lokal hochgeladene Bilder data/backups/ Automatische Migrationsbackups tests/ Integrations- und Sicherheitstests ``` ## Docker-Inbetriebnahme ### 1. Konfiguration anlegen Kopiere `.env.example` nach `.env` und ersetze die Beispielwerte: ```dotenv ADMIN_PASSWORD=EinLangesZufaelligesAdminPasswort SESSION_SECRET=EineUnabhaengigeZufaelligeZeichenfolgeMitMindestens32Zeichen # Optional: aktiviert den Klappentext-Assistenten GEMINI_API_KEY= # Nur setzen, wenn genau ein vertrauenswürdiger Reverse Proxy vorgeschaltet ist # TRUST_PROXY=1 ``` Für den Produktionsbetrieb gelten folgende Mindestanforderungen: - `ADMIN_PASSWORD`: gesetzt und mindestens 12 Zeichen lang - `SESSION_SECRET`: gesetzt, unabhängig vom Passwort und mindestens 32 Zeichen lang Ohne gültige Werte startet der Server im Produktionsmodus bewusst nicht. Geheimnisse gehören ausschließlich in `.env` beziehungsweise in die Secret-Verwaltung der Betriebsumgebung und nicht in `docker-compose.yml` oder Git. ### 2. Container starten ```bash docker compose up -d --build ``` Die Anwendung ist anschließend am veröffentlichten Container-Port `3000` erreichbar. In einer öffentlichen Installation sollte davor ein Reverse Proxy wie Caddy, Traefik oder Nginx Proxy Manager TLS übernehmen und ausschließlich die vorgesehenen Domains weiterleiten. Wenn genau ein vertrauenswürdiger Proxy vorgeschaltet und Port 3000 nicht direkt öffentlich erreichbar ist, kann `TRUST_PROXY=1` gesetzt werden. Das sorgt dafür, dass das Login-Limit die ursprüngliche Client-IP verwendet. Bei direkter Veröffentlichung des Ports darf diese Option nicht aktiviert werden. ## Installation ohne Docker Voraussetzung ist eine unterstützte Node.js-Version (empfohlen: Node.js 20 oder neuer). ```bash npm install npm run build NODE_ENV=production \ ADMIN_PASSWORD="EinLangesZufaelligesAdminPasswort" \ SESSION_SECRET="EineUnabhaengigeZufaelligeZeichenfolgeMitMindestens32Zeichen" \ npm start ``` Optional können `GEMINI_API_KEY`, `TRUST_PROXY`, `PORT` und `DATA_DIR` ergänzt werden. Standardmäßig lauscht die Anwendung auf Port `3000` und verwendet `./data` als Datenverzeichnis. Für die lokale Entwicklung genügt: ```bash npm install npm run dev ``` Die im Entwicklungsmodus vorhandenen Fallback-Secrets sind ausschließlich für lokale Entwicklung gedacht und werden in Produktion nicht akzeptiert. ## Admin-Authentifizierung und Schutzmaßnahmen Das Admin-Passwort wird nur beim Login übertragen und weder als Bearer-Token zurückgegeben noch im Browser gespeichert. Nach erfolgreicher Anmeldung wird eine zufällige, serverseitig verwaltete Sitzung erzeugt. - Sitzungsdauer: 24 Stunden - Cookie: `HttpOnly`, `SameSite=Strict`, in Produktion zusätzlich `Secure` - Sitzungen liegen nur im Arbeitsspeicher und enden spätestens bei einem Server-/Container-Neustart - Schreibende Admin-Anfragen werden auf gleiche Herkunft geprüft - Fehlgeschlagene Logins werden pro Client-IP begrenzt - Uploads und Gemini-Aufrufe besitzen zusätzliche Sitzungslimits - Sicherheitsheader und eine Content Security Policy werden serverseitig gesetzt Ein vergessenes Admin-Passwort wird über die Betriebsumgebung geändert; es gibt keine öffentliche Passwort-zurücksetzen-Funktion. ## Datenhaltung und Backups Alle Inhaltsdaten liegen in `data/database.json`. Docker bindet mit `./data:/app/data` das vollständige Datenverzeichnis auf dem Host ein. Damit bleiben Daten und Uploads beim Neubauen oder Ersetzen des Containers erhalten. Für ein vollständiges Backup sollte der gesamte Ordner `data/` gesichert werden: ```text data/database.json data/uploads/ data/backups/ ``` Schreibvorgänge auf die JSON-Datenbank erfolgen atomar und nacheinander. Vor schemaändernden Migrationen legt die Anwendung eine unveränderte Sicherung in `data/backups/` an. Diese lokalen Sicherungen ersetzen kein externes, regelmäßig getestetes Backup. ## Bild-Uploads Der Adminbereich akzeptiert JPEG, PNG, WebP, GIF und AVIF mit maximal 8 MB pro Datei. Der Server: - prüft Dateiendung, angegebenen MIME-Typ und den tatsächlichen Dateikopf, - lehnt SVG, HTML und andere aktive Formate ab, - erzeugt zufällige, nicht überschreibbare Dateinamen, - begrenzt Uploadversuche pro Admin-Sitzung und Stunde, - liefert Uploads mit `nosniff` und langfristigen Cache-Headern aus. Die Bilder können für Avatare, Banner, Buchcover und aktuelle Projekte verwendet werden. Leere Bildfelder erzeugen keinen Request zu einem externen Standardbild. ## Optionale Buttons im Zusatzabschnitt Im zusätzlichen Textabschnitt eines Profils können bis zu drei CTA-Buttons gepflegt werden. Jeder Button benötigt eine Beschriftung und eine vollständige `http://`- oder `https://`-Adresse. Unvollständige Einträge werden nicht angezeigt, andere URL-Schemata werden serverseitig abgelehnt. Die Buttons öffnen das Ziel in einem neuen Tab und werden automatisch mit den Akzentfarben des Profils gestaltet. Auf kleinen Bildschirmen stehen sie untereinander, auf größeren Bildschirmen nebeneinander. Damit können ausgewählte Pseudonyme bewusst miteinander verknüpft werden, ohne dass daraus eine automatische Verlinkung zu weiteren Profilen entsteht. ## Spotify und externe Dienste Spotify-Playlists werden sowohl in Buch- als auch in Projektdetails nach dem Zwei-Klick-Prinzip eingebunden. Beim Öffnen eines Details erscheint zunächst nur ein lokaler Platzhalter. Erst nach einem bewussten Klick auf „Spotify-Player laden“ wird das Spotify-`iframe` erzeugt und eine Verbindung zu Spotify hergestellt. Weitere mögliche externe Verbindungen: - `GEMINI_API_KEY`: Der optionale Admin-Assistent sendet die eingegebenen Buchinformationen serverseitig an die Google-Gemini-API. - Kauf- und sonstige Markdown-Links: Erst ein Klick führt zur jeweiligen externen Website. - Externe Bild-URLs: Das System unterstützt sie weiterhin, empfohlen werden jedoch lokal hochgeladene Bilder. Die Anwendung enthält kein Analytics- oder Tracking-System und lädt keine externen Webfonts. Sie verwendet für Besucher weder `localStorage` noch `sessionStorage`. Der Browser speichert lediglich das notwendige Admin-Sitzungscookie nach einer Anmeldung. Diese Punkte sowie das übliche Logging des Reverse Proxys/Hosters sollten passend zur tatsächlichen Installation in der Datenschutzerklärung beschrieben werden. ## SEO und Betriebsendpunkte - `/health/live`: Prozess läuft - `/health/ready`: Daten wurden geladen und der Server ist bereit - `/robots.txt`: profilabhängige Crawling-Regeln - `/sitemap.xml`: profilabhängige Sitemap - `/admin`: mit `noindex` gekennzeichneter Administrationsbereich Seitentitel, Beschreibung, Canonical URL, Open-Graph-Daten und strukturierte Personendaten werden serverseitig für die aufgerufene Domain erzeugt. Optionale SEO-Felder können je Profil im Adminbereich gepflegt werden; fehlende Angaben werden aus bestehenden Profildaten abgeleitet. ## Qualitätschecks ```bash npm run typecheck # TypeScript-Typprüfung npm test # Produktionsbuild und Integrationstests npm run check # Typprüfung, Build und Tests ``` Die Integrationstests verwenden ein temporäres Datenverzeichnis und einen kurzlebigen lokalen HTTP-Server. Geprüft werden unter anderem: - verpflichtende Produktions-Secrets, - Admin-Sitzung und Logout, - Origin-Schutz und Login-Limit, - exaktes Domain-Routing und öffentliche Profilisolation, - Schutz des vollständigen Admin-Datenendpunkts, - gültige und manipulierte Bild-Uploads, - wesentliche Sicherheitsheader. ## Hinweise zur Aktualisierung Vor einem Update sollte der komplette `data/`-Ordner gesichert werden. Danach kann das Image neu gebaut werden: ```bash docker compose up -d --build ``` Vorhandene Inhaltsdaten werden nicht durch die im Quellcode enthaltenen Ausgangsdaten ersetzt. Neue optionale Felder werden migrationsfähig ergänzt; vor notwendigen Schemaänderungen wird automatisch ein Backup angelegt.