ToolCTRL — Website

Mehrseitige Website im Visitenkarten-Stil: Landing Page mit Lead-Formular, TechDay-2026-Seite, AI-GameJam-Seite mit Datei-Upload sowie Impressum und Datenschutz. Monochrom (weiß / schwarz), an die ToolCTRL Brand Identity angelehnt. Der Server läuft ohne npm-Pakete (nur Node-Standardbibliothek).

Starten

node server.js

Der Server sucht automatisch einen freien Port (zuerst 4317) und gibt lokale und Netzwerk-URL aus. Stoppen mit Strg + C.

Voraussetzung: Node.js (getestet mit v26).

Qualitätschecks:

npm run check
npm test

Aufbau

public/             statische Website
  index.html        Landing Page + Kontaktformular
  techday.html      TechDay Bruchsal 2026
  gamejam.html      AI GameJam (eigenes Styling, Spiel-Upload)
  impressum.html    Impressum
  datenschutz.html  Datenschutzerklärung
  styles.css        Designsystem
  script.js         Formular-Logik & Mobile-Navigation
  assets/           Logos, Emblem, Favicon, Icons, Schriften, Mockups
server.js           abhängigkeitsfreier Node-HTTP-Server + API
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.

Plattform-Leads

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:

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)

POST /api/gamejam/upload nimmt eine .html-Datei entgegen (max. 5 MB). Jede hochgeladene Datei wird vor dem Speichern per ClamAV auf Viren geprüft. Befund → Ablehnung; ist der Scanner nicht erreichbar, wird der Upload ebenfalls abgelehnt (fail-closed, kein ungeprüftes Speichern).

Der Server spricht den ClamAV-Daemon clamd direkt über sein Socket-Protokoll an — keine zusätzliche Abhängigkeit. Voraussetzung: ClamAV ist installiert und clamd läuft. Beim Start meldet der Server Virenscan: aktiv bzw. eine Warnung, falls clamd nicht erreichbar ist.

ClamAV einrichten — macOS

brew install clamav
cd "$(brew --prefix)/etc/clamav"
cp freshclam.conf.sample freshclam.conf
cp clamd.conf.sample clamd.conf
# In BEIDEN Dateien die Zeile "Example" entfernen oder auskommentieren.
# In clamd.conf zusätzlich diese zwei Zeilen aktivieren (Raute entfernen):
#   TCPSocket 3310
#   TCPAddr 127.0.0.1
freshclam     # Virendefinitionen laden (einmalig)
clamd         # Daemon starten

ClamAV einrichten — Linux (Debian/Ubuntu)

sudo apt install clamav clamav-daemon
# In /etc/clamav/clamd.conf: TCPSocket 3310 und TCPAddr 127.0.0.1 setzen
sudo systemctl restart clamav-daemon

Konfiguration

Host/Port und An/Aus stehen in server.js im Objekt CLAMAV. Mit enabled: false läuft der Upload ohne Virenscan (nur für lokale Tests ohne ClamAV gedacht).

Per Environment kann der Runtime-Betrieb konfiguriert werden:

PORT=3000
HOST=0.0.0.0
DATA_DIR=/app/data
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 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

Eine Datei mit der EICAR-Testsignatur hochladen — clamd meldet dann Eicar-Test-Signature FOUND, der Upload wird abgelehnt.

Hinweis für die Messe

Für den QR-Code am Stand muss der Rechner im selben WLAN erreichbar sein. Soll die Seite öffentlich laufen, hinter einen Reverse-Proxy mit HTTPS setzen oder bei einem Hoster bereitstellen — tool-ctrl.de.

Deployment

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: vollständiger, unveränderlicher Commit-SHA und main.
  4. Coolify-App toolctrl-website (ocwtt7rd2zijtlszgua005k9) zieht :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.

S
Description
No description provided
Readme
3.5 MiB
0 Stars 9 Watchers 0 Forks
Languages
HTML 66.6%
CSS 18.2%
JavaScript 14.7%
Dockerfile 0.5%