feat(leads): submit contact requests to native platform intake

This commit is contained in:
Raffael Sheikh committed 2026-07-16 12:33:08 +02:00
1 parent 41664c3d0d
commit 079764d93d
12 files changed
+760 -154

No files matched your search

+50 -9
View File
@@ -16,6 +16,13 @@ und Netzwerk-URL aus. Stoppen mit `Strg + C`.
Voraussetzung: Node.js (getestet mit v26).
Qualitätschecks:
```bash
npm run check
npm test
```
## Aufbau
```
@@ -29,18 +36,46 @@ public/ statische Website
script.js Formular-Logik & Mobile-Navigation
assets/ Logos, Emblem, Favicon, Icons, Schriften, Mockups
server.js abhängigkeitsfreier Node-HTTP-Server + API
leads/ gesammelte Kontaktanfragen (wird automatisch angelegt)
leads/ historische NDJSON/CSV-Leads (nur noch Backfill-Quelle)
gamejam/ GameJam-Einreichungen, Metadaten (wird automatisch angelegt)
```
`leads/`, `gamejam/` und hochgeladene Spiele sind per `.gitignore` vom Repo
ausgeschlossen.
## Leads
## Plattform-Leads
`POST /api/lead` (JSON, Pflichtfelder `name`, `email`, `nachricht`). Jede
Anfrage landet sofort lokal in `leads/leads.csv` **und** `leads.ndjson` — so
geht auf der Messe nichts verloren. Ein Honeypot-Feld fängt einfache Bots ab.
`POST /api/lead` validiert das Kontaktformular serverseitig und sendet die
Anfrage an HiveGrids nativen Endpoint `POST /v1/platform/leads`. Pflichtfelder
sind `name`, `email`, `nachricht` und die vom Browser erzeugte `submissionId`.
Ein Honeypot-Feld fängt einfache Bots ab.
Der Browser behält die Submission-ID nach einem fehlgeschlagenen Versuch mit
semantisch gleichem Payload bei. Wird das Formular inhaltlich geändert, bindet er
vor dem nächsten Senden eine neue ID. Der Server verwendet dieselbe ID als
`externalId`, `metadata.submissionId` und `Idempotency-Key`; auch der einmalige
Netzwerk-/5xx-Retry verwendet exakt denselben Key und Payload. Dem Formular wird
nur dann Erfolg gemeldet, wenn die Plattform den Lead mit `201` angenommen hat.
API-, Netzwerk- und Konfigurationsfehler bleiben Fehler.
Die bisherige Zuordnung `Messe — Landing Page` bleibt im nativen Vertrag als
`sourceDetail` und `utmCampaign=messe-landing-page` erhalten.
Erforderliche Runtime-Variablen:
```bash
PLATFORM_LEADS_API_URL=https://api.hivegrid.de
PLATFORM_LEADS_API_KEY=<source-spezifischer Key für toolctrl-website, 32–512 Zeichen>
```
Der Bearer-Key gehört ausschließlich in die Server-Runtime (Coolify), nie ins
Repository oder nach `public/`. Ohne gültige Konfiguration liefert die Route
`503` und `/readyz` bleibt nicht bereit.
Die bestehenden Dateien `leads/leads.ndjson` und `leads/leads.csv` sind
Legacy-Bestände für den kontrollierten R-LEADS-Backfill. Der laufende Producer
erstellt oder verändert sie nicht mehr und meldet bei Plattformfehlern keinen
lokalen Ersatz-Erfolg.
## GameJam-Upload & Virenscan (ClamAV)
@@ -93,11 +128,15 @@ CLAMAV_HOST=127.0.0.1
CLAMAV_PORT=3310
CLAMAV_ENABLED=true
APP_REVISION=<git-sha>
PLATFORM_LEADS_API_URL=https://api.hivegrid.de
PLATFORM_LEADS_API_KEY=<Runtime-Secret>
```
`/healthz` ist die leichte Liveness-Probe für Container und Coolify.
`/readyz` prüft zusätzlich Schreibzugriff auf die Datenverzeichnisse und,
falls aktiv, die Erreichbarkeit von ClamAV.
`/readyz` prüft zusätzlich die Plattform-Lead-Konfiguration, Schreibzugriff auf
die GameJam-Datenverzeichnisse und, falls aktiv, die Erreichbarkeit von ClamAV.
Der Container-Healthcheck verwendet `/readyz`, damit eine fehlende
Plattform-Lead-Konfiguration einen Deploy nicht gesund erscheinen lässt.
### Funktion testen
@@ -117,9 +156,11 @@ Deployment folgt dem Gitea-Infra-Standard aus `toolctrl-labs/infra`:
1. Push auf `main` triggert `.gitea/workflows/deploy.yml`.
2. Gitea Actions baut das Docker-Image und pusht es nach
`git.tool-ctrl.de/toolctrl-labs/toolctrl-website`.
3. Tags: kurzer Commit-SHA und `main`.
3. Tags: vollständiger, unveränderlicher Commit-SHA und `main`.
4. Coolify-App `toolctrl-website` (`ocwtt7rd2zijtlszgua005k9`) zieht
`:main` auf der Marketing-VM und startet neu.
`:main` per erzwungenem Pull-Deploy auf der Marketing-VM.
5. Der Workflow wartet anschließend, bis `/readyz` erfolgreich ist und exakt
den ausgelieferten Commit-SHA als `revision` meldet.
Die Coolify-App läuft im Projekt `Marketing`, Environment `production`, Server
`marketing-vm`, Port `3000`, mit persistentem Storage auf `/app/data`.