init: extract hermes-recruiter from qognio-bot-widget-template@d2c816f

Source files (src/) and rendered bundle (www/) extracted on 2026-04-29T01:35:47+02:00.
Adds nginx:alpine Dockerfile + docker-compose.yml (Caddy-labels) so the bot
runs stand-alone or as a per-customer template clone.

Parent monorepo commit: d2c816f3edbc9760802a11b29ff4151c7aad4b46
Bot version: 2026-04-26
This commit is contained in:
Qognio Bot Extract 2026-04-29 01:35:47 +02:00
commit 4e6af8f8ac
16 changed files with 3209 additions and 0 deletions

7
.dockerignore Normal file
View file

@ -0,0 +1,7 @@
.git
.gitignore
README.md
bot.json
src/
docker-compose.yml
*.md

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
.DS_Store
*.log
*.tmp
node_modules/

13
Dockerfile Normal file
View file

@ -0,0 +1,13 @@
# Static-bundle bot — nginx:alpine serves www/ on port 80.
FROM nginx:1.27-alpine
# nginx config: gzip + cache headers + index.html no-store
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Static bundle
COPY www/ /usr/share/nginx/html/
# Run as non-root via nginx's built-in unprivileged image features
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -q --spider http://127.0.0.1/index.html || exit 1

67
README.md Normal file
View file

@ -0,0 +1,67 @@
# Helena — Hermes Logistics Recruiter
Helena — Recruiter-Bot für Hermes Logistics (Demo auf Qognio-Plattform). Fahrer, Lager, Disposition, IT. Sovereign-AI-Bunker DE. Nicht offiziell von Hermes autorisiert.
```
slug : hermes-recruiter
version : 2026-04-26
accent : #003C8F
runtime : nginx:alpine (static bundle)
template : qognio-bot-template-core (former qognio-bot-widget-template)
```
## Layout
```
.
├── src/ source — config.yaml, welcome.html, curricula.json, etc.
├── www/ rendered, directly servable static bundle
├── Dockerfile nginx:alpine + www/ → port 80
├── docker-compose.yml bot-host pattern (Caddy-labels, restart unless-stopped)
├── nginx.conf gzip + cache + SPA fallback
└── bot.json metadata + parent_core_commit
```
## Run locally
```bash
docker compose up --build
# → http://localhost (you'll need to tweak ports for local-only use)
```
## Re-render after upstream core changes
This repo only stores src + rendered output; the rendering engine lives in
`qognio-bot-template-core`. To pull in core changes:
```bash
cd /path/to/qognio-bot-template-core
./scripts/render.sh hermes-recruiter --bot-repo /path/to/this/repo
git -C /path/to/this/repo commit -am "render: refresh from core@<sha>"
```
## Per-customer copy (template usage)
This repo is a **template**. To clone for a customer:
```bash
git clone <this-repo> my-customer-hermes-recruiter
cd my-customer-hermes-recruiter
# tweak src/config.yaml (slug, bot_key_value, accent), src/welcome.html, src/curricula.json
docker compose -f docker-compose.yml up --build
```
## Deploy to qognio bot-host (.42 LXC pattern — legacy)
The bot-manager spawns LXC containers named after the slug. Push www/ via:
```bash
ssh fmh@46.243.203.42
sudo lxc file push /tmp/www/* hermes-recruiter/var/www/html/
```
(Or run the docker-compose pattern on a Docker host — same network as Caddy.)
---
Generated by `qognio-bot-template-core/scripts/extract-to-repo.sh` on 2026-04-29T01:35:47+02:00.

14
bot.json Normal file
View file

@ -0,0 +1,14 @@
{
"slug": "hermes-recruiter",
"name": "Helena",
"title": "Hermes Logistics Recruiter",
"tagline": "Recruiter-Bot",
"description": "Helena — Recruiter-Bot für Hermes Logistics (Demo auf Qognio-Plattform). Fahrer, Lager, Disposition, IT. Sovereign-AI-Bunker DE. Nicht offiziell von Hermes autorisiert.",
"version": "2026-04-26",
"accent": "#003C8F",
"extracted_from": "qognio-bot-widget-template",
"parent_core_commit": "d2c816f3edbc9760802a11b29ff4151c7aad4b46",
"extracted_at": "2026-04-29T01:35:47+02:00",
"runtime": "nginx:alpine",
"default_port": 80
}

20
docker-compose.yml Normal file
View file

@ -0,0 +1,20 @@
# Stand-alone bot container.
# Designed for the "caddy" external network on the bot host (qognio pattern).
# Override the hostname via SLUG env var if you reuse this template per customer.
services:
bot:
build: .
image: qognio/bot-hermes-recruiter:${TAG:-latest}
container_name: bot-hermes-recruiter
restart: unless-stopped
networks:
- caddy
labels:
caddy: "hermes-recruiter.on.qognio.com"
caddy.reverse_proxy: "{{upstreams 80}}"
qognio.bot.slug: "hermes-recruiter"
qognio.bot.version: "2026-04-26"
networks:
caddy:
external: true

27
nginx.conf Normal file
View file

@ -0,0 +1,27 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# gzip
gzip on;
gzip_vary on;
gzip_types text/css application/javascript application/json image/svg+xml text/plain;
gzip_min_length 512;
# index.html: never cache (so welcome screen / wiring updates land instantly)
location = /index.html {
add_header Cache-Control "no-store, must-revalidate" always;
}
# static assets: cache 1h
location ~* \.(?:css|js|json|svg|png|jpe?g|webp|gif|ico|woff2?)$ {
add_header Cache-Control "public, max-age=3600" always;
try_files $uri =404;
}
location / {
try_files $uri $uri/ /index.html;
}
}

19
src/check-badges.js Normal file
View file

@ -0,0 +1,19 @@
// DSGVO-Erstkontakt — 1 Modul "dsgvo-grundlagen" Quiz korrekt
if ((state.moduleCorrect && state.moduleCorrect['dsgvo-grundlagen'] >= 1)) unlockBadge('dsgvo_erstkontakt');
// AI-Act-Spürnase — Modul "ai-act" Quiz mit ≥3 korrekt
if ((state.moduleCorrect && state.moduleCorrect['ai-act'] >= 3)) unlockBadge('ai_act_spuernase');
// NIS2-Versteher:in — Modul "nis2" Quiz mit ≥3 korrekt
if ((state.moduleCorrect && state.moduleCorrect['nis2'] >= 3)) unlockBadge('nis2_versteher');
// GoBD-Kenner:in — Modul "gobd" Quiz bestanden
if ((state.moduleCorrect && state.moduleCorrect['gobd'] >= 3)) unlockBadge('gobd_kenner');
// Mittelstands-Lotse — Schwellenwert-Modul (Flashcards bestanden ODER Quiz mit ≥3 korrekt)
if ((state.modulePassedFlash && state.modulePassedFlash['schwellenwerte-uebersicht']) ||
(state.moduleCorrect && state.moduleCorrect['schwellenwerte-uebersicht'] >= 3)) unlockBadge('mittelstands_lotse');
// Compliance-Generalist:in — mindestens 4 Module mit ≥80% abgeschlossen (Module aus 4 Säulen)
if ((state.completedCurricula || []).length >= 4) unlockBadge('compliance_generalist');
// Compliance-Disziplin — 14-Tage-Streak
if (state.maxStreak >= 14) unlockBadge('streak_14');
// Night Owl & Early Bird (beibehalten)
const h = new Date().getHours();
if (h >= 22) unlockBadge('night_owl');
if (h < 7) unlockBadge('early_bird');

34
src/config.yaml Normal file
View file

@ -0,0 +1,34 @@
slug: hermes-recruiter
bot_name: Helena
bot_title: Hermes Logistics Recruiter
brand_letter: H
title: "Helena · Karriere bei Hermes Logistics"
tagline: "Recruiter-Bot — Demo auf Qognio"
tagline_short: Recruiter-Bot
meta_description: "Helena — Recruiter-Bot für Hermes Logistics (Demo auf Qognio-Plattform). Fahrer, Lager, Disposition, IT. Sovereign-AI-Bunker DE. Nicht offiziell von Hermes autorisiert."
bot_key_var: __HELENA_KEY__
bot_key_value: qb_hrl5zfev5e
ls_prefix: helena
bot_version: "2026-04-26"
# Color theme — Hermes-CI Blau (Otto Group) + Orange-Akzent
accent: "#003C8F"
accent_2: "#1858B5"
accent_dark: "#002B6B"
accent_rgb: "0, 60, 143"
accent_rgb_compact: "0,60,143"
success_color: "#FF6900"
msg_strong_color: "#A0BEEE"
# UI Labels
tab_flash_label: "Stellen"
tab_curriculum_label: "FAQ"
# Bot-personality strings
quiz_intro_hint: "Helena führt dich durch die typischen Bewerbungs-Fragen pro Berufsbild."
quiz_verb: stellt
quiz_noun: "Bewerbungs-Fragen"
flash_intro_hint: "Aktuelle Stellen, gefiltert nach Region + Berufsbild."
flash_verb: zeigt
curriculum_long_label: FAQ

33
src/curricula.json Normal file
View file

@ -0,0 +1,33 @@
{
"version": "2026-04-26",
"updated": "2026-04-26",
"curricula": [
{
"id": "berufsbilder",
"title": "1 · Berufsbilder bei Hermes Logistics",
"short": "Fahrer / Lager / Büro & IT",
"icon": "users",
"color": "#003C8F",
"description": "Übersicht der Berufsbilder: Berufskraftfahrer C/CE, Lager-Mitarbeitende, Disposition, IT, Niederlassungsleitung.",
"source_md": "stellenprofile.md",
"modules": [
{"id": "fahrer", "title": "Berufskraftfahrer C/CE", "objectives":["BKrFQG-Pflichten kennen","Schichtmodelle einschätzen","Lohnrahmen verstehen"], "topics":["BKrFQG","Schicht","ADR","KEP-Markt"], "difficulty":"einfach", "source_heading":"Fahrer"},
{"id": "lager", "title": "Lager + Schichtleitung", "objectives":["Stapler-Schein-Regelungen","Schichtmodelle","Aufstiegspfade"], "topics":["Stapler","WMS","SAP-EWM","Schicht"], "difficulty":"mittel", "source_heading":"Lager"},
{"id": "buero-it", "title": "Disposition, IT, Office", "objectives":["Tourenplanungs-Software","Disposition-Skills","IT-Stack"], "topics":["Disposition","SAP","AWS","DevOps"], "difficulty":"mittel", "source_heading":"Büro & IT"}
]
},
{
"id": "bewerbung",
"title": "2 · Bewerbungsprozess",
"short": "Erstkontakt → Auswahl → Hospitanz → Vertrag",
"icon": "briefcase",
"color": "#FF6900",
"description": "So läuft eine Bewerbung bei Hermes Logistics ab.",
"source_md": "bewerbungsprozess.md",
"modules": [
{"id": "erstkontakt", "title": "Erstkontakt + Vorqualifikation", "objectives":["Welche Daten gefragt werden","Wer prüft was"], "topics":["CV","Vorgespräch"], "difficulty":"einfach", "source_heading":"Erstkontakt"},
{"id": "hospitanz", "title": "Hospitanz / Probearbeitstag", "objectives":["Was Hospitanz bedeutet","Aufwandsentschädigung"], "topics":["Hospitanz","Probearbeit"], "difficulty":"mittel", "source_heading":"Hospitanz"}
]
}
]
}

4
src/levels-fallback.js Normal file
View file

@ -0,0 +1,4 @@
{ min: 0, title: 'Pflicht-Anfänger:in' }, { min: 50, title: 'Pflicht-Spürnase' },
{ min: 200, title: 'Compliance-Generalist:in' }, { min: 500, title: 'Compliance-Lotse' },
{ min: 1250, title: 'Senior-Compliance-Manager:in' }, { min: 2500, title: 'Compliance-Architekt:in' },
{ min: 5000, title: 'Compliance-Veteran:in' }

25
src/welcome.html Normal file
View file

@ -0,0 +1,25 @@
<h2>Hi, ich bin Helena.</h2>
<p>Ich bin der <strong>Recruiter-Bot von Hermes Logistics</strong> — eine Demo auf der Qognio-Plattform. Ich nehme deine Bewerbung strukturiert auf, prüfe welche Stelle passt, und übergebe an einen echten Menschen aus dem Talent-Acquisition-Team. <strong>Disclaimer:</strong> Ich bin ein KI-Bot, nicht offiziell von Hermes autorisiert.</p>
<div class="mode-grid">
<button class="mode-card" data-goto="chat">
<strong>Chat</strong>
<span>Sag mir was du suchst — Region, Berufsbild, Vollzeit/Teilzeit.</span>
</button>
<button class="mode-card" data-prompt="Welche Berufskraftfahrer-Stellen habt ihr aktuell offen?">
<strong>Fahrer-Stellen</strong>
<span>Direkt zeigen: aktuelle BKF-C/CE-Stellen.</span>
</button>
<button class="mode-card" data-prompt="Welche Lager-Stellen habt ihr aktuell? Ich kann auch Schicht.">
<strong>Lager-Stellen</strong>
<span>Kommissionierer, Schichtleitung, Stapler.</span>
</button>
<button class="mode-card" data-prompt="Welche Büro-/Disposition-/IT-Stellen habt ihr offen?">
<strong>Büro & IT</strong>
<span>Disposition, Office, IT, Niederlassungsleitung.</span>
</button>
<button class="mode-card" data-goto="curriculum">
<strong>FAQ</strong>
<span>Bezahlung, Urlaub, Übernahme, Quereinstieg.</span>
</button>
</div>
<p style="font-size:.82rem;color:var(--text-mute)">Lade gerne deinen Lebenslauf hoch (📎-Button) — ich prüfe die Eckdaten und mach dir einen Vorschlag, welche Stelle passt. Am Ende verbinde ich dich mit einem Recruiter.</p>

1750
www/app.js Normal file

File diff suppressed because it is too large Load diff

33
www/curricula.json Normal file
View file

@ -0,0 +1,33 @@
{
"version": "2026-04-26",
"updated": "2026-04-26",
"curricula": [
{
"id": "berufsbilder",
"title": "1 · Berufsbilder bei Hermes Logistics",
"short": "Fahrer / Lager / Büro & IT",
"icon": "users",
"color": "#003C8F",
"description": "Übersicht der Berufsbilder: Berufskraftfahrer C/CE, Lager-Mitarbeitende, Disposition, IT, Niederlassungsleitung.",
"source_md": "stellenprofile.md",
"modules": [
{"id": "fahrer", "title": "Berufskraftfahrer C/CE", "objectives":["BKrFQG-Pflichten kennen","Schichtmodelle einschätzen","Lohnrahmen verstehen"], "topics":["BKrFQG","Schicht","ADR","KEP-Markt"], "difficulty":"einfach", "source_heading":"Fahrer"},
{"id": "lager", "title": "Lager + Schichtleitung", "objectives":["Stapler-Schein-Regelungen","Schichtmodelle","Aufstiegspfade"], "topics":["Stapler","WMS","SAP-EWM","Schicht"], "difficulty":"mittel", "source_heading":"Lager"},
{"id": "buero-it", "title": "Disposition, IT, Office", "objectives":["Tourenplanungs-Software","Disposition-Skills","IT-Stack"], "topics":["Disposition","SAP","AWS","DevOps"], "difficulty":"mittel", "source_heading":"Büro & IT"}
]
},
{
"id": "bewerbung",
"title": "2 · Bewerbungsprozess",
"short": "Erstkontakt → Auswahl → Hospitanz → Vertrag",
"icon": "briefcase",
"color": "#FF6900",
"description": "So läuft eine Bewerbung bei Hermes Logistics ab.",
"source_md": "bewerbungsprozess.md",
"modules": [
{"id": "erstkontakt", "title": "Erstkontakt + Vorqualifikation", "objectives":["Welche Daten gefragt werden","Wer prüft was"], "topics":["CV","Vorgespräch"], "difficulty":"einfach", "source_heading":"Erstkontakt"},
{"id": "hospitanz", "title": "Hospitanz / Probearbeitstag", "objectives":["Was Hospitanz bedeutet","Aufwandsentschädigung"], "topics":["Hospitanz","Probearbeit"], "difficulty":"mittel", "source_heading":"Hospitanz"}
]
}
]
}

121
www/index.html Normal file
View file

@ -0,0 +1,121 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Helena · Karriere bei Hermes Logistics</title>
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<meta name="theme-color" content="#0a0a0f">
<meta name="description" content="Helena — Recruiter-Bot für Hermes Logistics (Demo auf Qognio-Plattform). Fahrer, Lager, Disposition, IT. Sovereign-AI-Bunker DE. Nicht offiziell von Hermes autorisiert.">
<link rel="stylesheet" href="styles.css">
<script>window.__HELENA_KEY__ = 'qb_hrl5zfev5e';</script>
</head>
<body>
<div class="app" role="application" aria-label="Helena Recruiter-Bot — Demo auf Qognio">
<header class="topbar">
<div class="brand">
<span class="brand-icon" aria-hidden="true">H</span>
<span>Helena <small>Recruiter-Bot</small></span>
</div>
<div class="spacer"></div>
<span class="status" role="status" aria-live="polite">Online</span>
</header>
<nav class="tabbar" role="tablist" aria-label="Modi">
<button class="tab" role="tab" aria-selected="true" aria-controls="view-chat" data-mode="chat">
Chat
<span class="tab-kbd">⌃1</span>
</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="view-quiz" data-mode="quiz">
Quiz
<span class="tab-kbd">⌃2</span>
</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="view-flash" data-mode="flash">
Stellen
<span class="tab-kbd">⌃3</span>
</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="view-progress" data-mode="progress">
Fortschritt
<span class="tab-kbd">⌃4</span>
</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="view-curriculum" data-mode="curriculum">
FAQ
<span class="tab-kbd">⌃5</span>
</button>
</nav>
<main class="main">
<!-- CHAT -->
<section id="view-chat" class="view" role="tabpanel" aria-labelledby="tab-chat" data-active="true">
<div id="welcome-screen" class="welcome hidden" aria-hidden="true">
<h2>Hi, ich bin Helena.</h2>
<p>Ich bin der <strong>Recruiter-Bot von Hermes Logistics</strong> — eine Demo auf der Qognio-Plattform. Ich nehme deine Bewerbung strukturiert auf, prüfe welche Stelle passt, und übergebe an einen echten Menschen aus dem Talent-Acquisition-Team. <strong>Disclaimer:</strong> Ich bin ein KI-Bot, nicht offiziell von Hermes autorisiert.</p>
<div class="mode-grid">
<button class="mode-card" data-goto="chat">
<strong>Chat</strong>
<span>Sag mir was du suchst — Region, Berufsbild, Vollzeit/Teilzeit.</span>
</button>
<button class="mode-card" data-prompt="Welche Berufskraftfahrer-Stellen habt ihr aktuell offen?">
<strong>Fahrer-Stellen</strong>
<span>Direkt zeigen: aktuelle BKF-C/CE-Stellen.</span>
</button>
<button class="mode-card" data-prompt="Welche Lager-Stellen habt ihr aktuell? Ich kann auch Schicht.">
<strong>Lager-Stellen</strong>
<span>Kommissionierer, Schichtleitung, Stapler.</span>
</button>
<button class="mode-card" data-prompt="Welche Büro-/Disposition-/IT-Stellen habt ihr offen?">
<strong>Büro & IT</strong>
<span>Disposition, Office, IT, Niederlassungsleitung.</span>
</button>
<button class="mode-card" data-goto="curriculum">
<strong>FAQ</strong>
<span>Bezahlung, Urlaub, Übernahme, Quereinstieg.</span>
</button>
</div>
<p style="font-size:.82rem;color:var(--text-mute)">Lade gerne deinen Lebenslauf hoch (📎-Button) — ich prüfe die Eckdaten und mach dir einen Vorschlag, welche Stelle passt. Am Ende verbinde ich dich mit einem Recruiter.</p>
</div>
<div id="chat-box" class="chat-box" aria-live="polite" aria-label="Gespräch"></div>
</section>
<!-- QUIZ -->
<section id="view-quiz" class="view" role="tabpanel" aria-labelledby="tab-quiz">
<div id="quiz-host"></div>
</section>
<!-- FLASHCARDS -->
<section id="view-flash" class="view" role="tabpanel" aria-labelledby="tab-flash">
<div id="flash-host"></div>
</section>
<!-- PROGRESS -->
<section id="view-progress" class="view" role="tabpanel" aria-labelledby="tab-progress">
<div id="progress-host"></div>
</section>
<!-- CURRICULUM -->
<section id="view-curriculum" class="view" role="tabpanel" aria-labelledby="tab-curr">
<div id="curr-host"></div>
</section>
</main>
<form id="composer-form" class="composer" aria-label="Nachricht verfassen">
<div id="attach-strip" class="attach-strip" aria-live="polite"></div>
<div class="composer-row">
<button type="button" class="btn-attach" id="composer-attach" aria-label="Datei anhängen" title="Datei anhängen (PDF, Bild, Text — max 5 Dateien, 8 MB)">📎</button>
<input type="file" id="composer-file" multiple accept=".pdf,.txt,.md,.csv,.json,.xml,.yaml,.yml,.log,.png,.jpg,.jpeg,.webp,.gif" hidden>
<textarea id="composer" rows="1" placeholder="Frag Helena — Enter zum Senden, Shift+Enter für Zeilenumbruch" aria-label="Nachricht"></textarea>
<button type="submit" class="btn-primary" id="composer-send">Senden</button>
</div>
</form>
<footer class="footer">
Sovereign AI · Deutscher Bunker · <a href="https://qognio.com">Qognio</a> &nbsp;·&nbsp; DSGVO-konform · Keine externen Fonts · Keine Cookies
</footer>
</div>
<div id="toast-stack" class="toast-stack" aria-live="polite"></div>
<script src="app.js"></script>
</body>
</html>

1038
www/styles.css Normal file

File diff suppressed because it is too large Load diff