init: extract libra-handwerks-coach from qognio-bot-widget-template@d2c816f
Source files (src/) and rendered bundle (www/) extracted on 2026-04-29T01:35:48+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-25
This commit is contained in:
commit
123f9d082c
16 changed files with 3865 additions and 0 deletions
7
.dockerignore
Normal file
7
.dockerignore
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
README.md
|
||||||
|
bot.json
|
||||||
|
src/
|
||||||
|
docker-compose.yml
|
||||||
|
*.md
|
||||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
.DS_Store
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
node_modules/
|
||||||
13
Dockerfile
Normal file
13
Dockerfile
Normal 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
67
README.md
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# LIBRA — Handwerks-Kalkulations-Coach
|
||||||
|
|
||||||
|
LIBRA — der Kalkulations-Sparringspartner für SHK/Elektro/Maler/Tischler. Stundensätze, Materialaufschläge, Nachkalkulation. Im deutschen Bunker.
|
||||||
|
|
||||||
|
```
|
||||||
|
slug : libra-handwerks-coach
|
||||||
|
version : 2026-04-25
|
||||||
|
accent : #d97706
|
||||||
|
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 libra-handwerks-coach --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-libra-handwerks-coach
|
||||||
|
cd my-customer-libra-handwerks-coach
|
||||||
|
# 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/* libra-handwerks-coach/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:48+02:00.
|
||||||
14
bot.json
Normal file
14
bot.json
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"slug": "libra-handwerks-coach",
|
||||||
|
"name": "LIBRA",
|
||||||
|
"title": "Handwerks-Kalkulations-Coach",
|
||||||
|
"tagline": "Kalkulationscoach",
|
||||||
|
"description": "LIBRA — der Kalkulations-Sparringspartner für SHK/Elektro/Maler/Tischler. Stundensätze, Materialaufschläge, Nachkalkulation. Im deutschen Bunker.",
|
||||||
|
"version": "2026-04-25",
|
||||||
|
"accent": "#d97706",
|
||||||
|
"extracted_from": "qognio-bot-widget-template",
|
||||||
|
"parent_core_commit": "d2c816f3edbc9760802a11b29ff4151c7aad4b46",
|
||||||
|
"extracted_at": "2026-04-29T01:35:48+02:00",
|
||||||
|
"runtime": "nginx:alpine",
|
||||||
|
"default_port": 80
|
||||||
|
}
|
||||||
20
docker-compose.yml
Normal file
20
docker-compose.yml
Normal 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-libra-handwerks-coach:${TAG:-latest}
|
||||||
|
container_name: bot-libra-handwerks-coach
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- caddy
|
||||||
|
labels:
|
||||||
|
caddy: "libra-handwerks-coach.on.qognio.com"
|
||||||
|
caddy.reverse_proxy: "{{upstreams 80}}"
|
||||||
|
qognio.bot.slug: "libra-handwerks-coach"
|
||||||
|
qognio.bot.version: "2026-04-25"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
caddy:
|
||||||
|
external: true
|
||||||
27
nginx.conf
Normal file
27
nginx.conf
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/check-badges.js
Normal file
16
src/check-badges.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Erste Kalkulation — 1 Quiz im Lohnnebenkosten-Modul (Stundensatz-Curriculum)
|
||||||
|
if ((state.moduleCorrect && state.moduleCorrect['lohnnebenkosten'] >= 1)) unlockBadge('erste_kalkulation');
|
||||||
|
// Gewerks-Meister — 5 Quiz korrekt im SHK-Modul (Kern-Gewerk)
|
||||||
|
if ((state.moduleCorrect && state.moduleCorrect['shk'] >= 5)) unlockBadge('gewerks_meister');
|
||||||
|
// Marge-Optimierer — 3 Quiz korrekt im Soll-Ist-Vergleich-Modul (Nachkalkulation)
|
||||||
|
if ((state.moduleCorrect && state.moduleCorrect['soll-ist-vergleich'] >= 3)) unlockBadge('marge_optimierer');
|
||||||
|
// Fallen-Kenner — 5 Quiz korrekt im Fallen-Allgemein-Modul
|
||||||
|
if ((state.moduleCorrect && state.moduleCorrect['fallen-allgemein'] >= 5)) unlockBadge('fallen_kenner');
|
||||||
|
// LIBRA-Meister — 18 von 23 Modulen mit ≥80% Quiz-Score abgeschlossen (~78% Master-Coverage)
|
||||||
|
if ((state.completedCurricula || []).length >= 18) unlockBadge('libra_meister');
|
||||||
|
// Streak-7 — 7-Tage-Streak
|
||||||
|
if (state.maxStreak >= 7) unlockBadge('streak_7');
|
||||||
|
// Night Owl & Early Bird (beibehalten)
|
||||||
|
const h = new Date().getHours();
|
||||||
|
if (h >= 22) unlockBadge('night_owl');
|
||||||
|
if (h < 7) unlockBadge('early_bird');
|
||||||
38
src/config.yaml
Normal file
38
src/config.yaml
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
slug: libra-handwerks-coach
|
||||||
|
bot_name: LIBRA
|
||||||
|
bot_title: Handwerks-Kalkulations-Coach
|
||||||
|
brand_letter: L
|
||||||
|
title: "LIBRA · Dein Handwerks-Kalkulationscoach"
|
||||||
|
tagline: Handwerks-Kalkulationscoach
|
||||||
|
tagline_short: Kalkulationscoach
|
||||||
|
meta_description: "LIBRA — der Kalkulations-Sparringspartner für SHK/Elektro/Maler/Tischler. Stundensätze, Materialaufschläge, Nachkalkulation. Im deutschen Bunker."
|
||||||
|
bot_key_var: __LIBRA_KEY__
|
||||||
|
bot_key_value: qb_pz7hy9gkl1du
|
||||||
|
ls_prefix: libra
|
||||||
|
bot_version: "2026-04-25"
|
||||||
|
|
||||||
|
# Color theme — warm amber, distinct from Max (#f59e0b)
|
||||||
|
accent: "#d97706"
|
||||||
|
accent_2: "#f59e0b"
|
||||||
|
accent_dark: "#b45309"
|
||||||
|
accent_rgb: "217, 119, 6"
|
||||||
|
accent_rgb_compact: "217,119,6"
|
||||||
|
success_color: "#22c55e"
|
||||||
|
msg_strong_color: "#fcd34d"
|
||||||
|
|
||||||
|
# UI Labels
|
||||||
|
tab_flash_label: Karten
|
||||||
|
tab_curriculum_label: Gewerke
|
||||||
|
curriculum_long_label: Gewerke-Bibliothek
|
||||||
|
|
||||||
|
# Bot-personality strings
|
||||||
|
quiz_intro_hint: "Wähle ein Modul — LIBRA generiert Szenario-Fragen aus dem Handwerksalltag."
|
||||||
|
quiz_verb: erstellt
|
||||||
|
quiz_noun: "Szenario-Fragen"
|
||||||
|
flash_intro_hint: "Karteikarten zu Stundensatz-Formeln, Aufmaß, Gewerks-Spezifika — mit Spaced-Repetition."
|
||||||
|
flash_verb: generiert
|
||||||
|
|
||||||
|
# Levels-fallback, welcome.html, check-badges.js are sibling files
|
||||||
|
# in this directory — render.sh injects their full contents into the
|
||||||
|
# corresponding {{LEVELS_FALLBACK}}, {{WELCOME_HTML}}, {{CHECK_BADGES_BODY}}
|
||||||
|
# placeholders verbatim.
|
||||||
358
src/curricula.json
Normal file
358
src/curricula.json
Normal file
|
|
@ -0,0 +1,358 @@
|
||||||
|
{
|
||||||
|
"version": "2026-04-25",
|
||||||
|
"updated": "2026-04-25",
|
||||||
|
"curricula": [
|
||||||
|
{
|
||||||
|
"id": "stundensatz",
|
||||||
|
"title": "1 · Stundensatz & Lohnnebenkosten",
|
||||||
|
"short": "Vollkostendeckender SVS bilden",
|
||||||
|
"icon": "clock",
|
||||||
|
"color": "#d97706",
|
||||||
|
"description": "Vom Bruttolohn zum vollkostendeckenden Stundenverrechnungssatz: Lohnnebenkosten korrekt aufschlagen, produktive Stunden realistisch ansetzen, Gemeinkosten verteilen, Wagnis- und Gewinnzuschlag.",
|
||||||
|
"source_md": "01-stundensatz-bilden.md",
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "lohnnebenkosten",
|
||||||
|
"title": "Lohnnebenkosten korrekt aufschlagen",
|
||||||
|
"objectives": [
|
||||||
|
"Standard-Aufschlag 75-80% auf Brutto kennen",
|
||||||
|
"SOKA-Bau-Spezifikum verstehen (Faktor bis 105%)",
|
||||||
|
"Berufsgenossenschaft je Gewerk einordnen"
|
||||||
|
],
|
||||||
|
"topics": ["Sozialabgaben", "Urlaub", "Krankheit", "BG", "SOKA-Bau"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Schritt 2 — Lohnnebenkosten aufschlagen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "produktive-stunden",
|
||||||
|
"title": "Produktive Stunden realistisch",
|
||||||
|
"objectives": [
|
||||||
|
"1.400-1.650 h/Jahr als Realität akzeptieren",
|
||||||
|
"Abzüge sauber rechnen (Urlaub, Krankheit, Schulung, Werkstatt)",
|
||||||
|
"Wirkung von 200 h Differenz auf SVS verstehen"
|
||||||
|
],
|
||||||
|
"topics": ["Produktivstunden", "Auslastung", "1.436-h-Beispiel"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Schritt 3 — Produktive Stunden ermitteln"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gemeinkosten",
|
||||||
|
"title": "Gemeinkosten verteilen",
|
||||||
|
"objectives": [
|
||||||
|
"Werkstatt + Fuhrpark + Verwaltung + Versicherungen + Marketing erfassen",
|
||||||
|
"Pro produktiver Stunde umlegen",
|
||||||
|
"4-Mann-Beispielrechnung durchgehen (122k €/Jahr → 28,30 €/h)"
|
||||||
|
],
|
||||||
|
"topics": ["Werkstatt", "Fuhrpark", "Verwaltung", "Umlage"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Schritt 4 — Gemeinkosten verteilen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "wagnis-gewinn",
|
||||||
|
"title": "Wagnis- und Gewinnzuschlag",
|
||||||
|
"objectives": [
|
||||||
|
"Wagniszuschlag 5-10% als Pflicht erkennen",
|
||||||
|
"Gewinnzuschlag 8-15% als Substanz-Erhalt verstehen",
|
||||||
|
"5%-Falle vermeiden (Substanzverzehr)"
|
||||||
|
],
|
||||||
|
"topics": ["Wagnis", "Gewinn", "Forderungsausfall", "Substanz"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Schritt 5 — Wagniszuschlag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "svs-formel",
|
||||||
|
"title": "SVS-Endformel + Marktvergleich",
|
||||||
|
"objectives": [
|
||||||
|
"Vollständige SVS-Formel anwenden können",
|
||||||
|
"75-Euro-Standard kritisch hinterfragen",
|
||||||
|
"Regionale Spreizung kennen (Berlin/München vs Sachsen/Thüringen)"
|
||||||
|
],
|
||||||
|
"topics": ["SVS-Formel", "Marktpreis", "regionale Spreizung"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Schritt 7 — Vollständige SVS-Formel"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "material",
|
||||||
|
"title": "2 · Materialaufschlag & Skonto",
|
||||||
|
"short": "Aufschlag, Marge, Verschnitt, Skonto-Strategie",
|
||||||
|
"icon": "package",
|
||||||
|
"color": "#f59e0b",
|
||||||
|
"description": "Materialaufschlag richtig kalkulieren: Aufschlag vs. Marge, Skonto als Margen-Killer, Verschnitt-Reserve, Sondermaterial-Beschaffungspauschale, Lieferanten-Lock-in vermeiden.",
|
||||||
|
"source_md": "02-materialaufschlag.md",
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "aufschlag-grundlagen",
|
||||||
|
"title": "Was deckt der Materialaufschlag",
|
||||||
|
"objectives": [
|
||||||
|
"6 Kostenblöcke des Aufschlags benennen",
|
||||||
|
"Übliche Aufschläge nach Materialklasse kennen",
|
||||||
|
"Faustregel 25% auf EK als Standard-Mitte"
|
||||||
|
],
|
||||||
|
"topics": ["Bestellung", "Transport", "Lager", "Verschnitt", "Vorfinanzierung", "Gewährleistung"],
|
||||||
|
"difficulty": "einfach",
|
||||||
|
"source_heading": "Was deckt der Materialaufschlag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "aufschlag-vs-marge",
|
||||||
|
"title": "Aufschlag vs. Marge — kein Verwechslungsfehler",
|
||||||
|
"objectives": [
|
||||||
|
"25% Aufschlag = 20% Marge sicher umrechnen",
|
||||||
|
"Bei Lieferanten-Gespräch korrekt nachfragen",
|
||||||
|
"5%-Lücke pro 100k Material berechnen können"
|
||||||
|
],
|
||||||
|
"topics": ["Aufschlag-Formel", "Marge-Formel"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Aufschlag vs. Marge — der ewige Verwechslungsfehler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "skonto",
|
||||||
|
"title": "Skonto-Strategie",
|
||||||
|
"objectives": [
|
||||||
|
"Skonto immer in Kalkulation einrechnen",
|
||||||
|
"Skonto immer ziehen (Liquiditäts-Disziplin)",
|
||||||
|
"2% Skonto als 30-50% des Gewinns einordnen"
|
||||||
|
],
|
||||||
|
"topics": ["2/14 Tage", "Kalkulationsskonto", "Liquidität"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Skonto — der unterschätzte Margenkiller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "verschnitt",
|
||||||
|
"title": "Verschnitt-Reserve pro Material",
|
||||||
|
"objectives": [
|
||||||
|
"Materialspezifische Verschnitt-Quoten kennen",
|
||||||
|
"Verschnitt kalkulieren, nicht abrechnen",
|
||||||
|
"Tapeten-Rapport bis 25% beachten"
|
||||||
|
],
|
||||||
|
"topics": ["Kupferrohr", "Kabel", "Tapeten", "Fliesen", "Holz"],
|
||||||
|
"difficulty": "einfach",
|
||||||
|
"source_heading": "Verschnitt-Reserve"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gewerks-spezifika",
|
||||||
|
"title": "3 · Gewerke-Spezifika",
|
||||||
|
"short": "SHK / Elektro / Maler / Tischler im Detail",
|
||||||
|
"icon": "layers",
|
||||||
|
"color": "#b45309",
|
||||||
|
"description": "Pro Gewerk: typische Stundensätze, Material-Mix, Kalkulationsfallen, Rechtsrahmen (DIN VDE, DIN 1988, DIN 18363), VOB/B vs BGB, Gewährleistung 5J Bau / 2J BGB.",
|
||||||
|
"source_md": "07-rollen-spezifisch-shk-elektro-maler-tischler.md",
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "shk",
|
||||||
|
"title": "SHK — Sanitär/Heizung/Klima",
|
||||||
|
"objectives": [
|
||||||
|
"Stundensatz 75-115 EUR/h einordnen",
|
||||||
|
"DIN 1988-200 Spülung + Druckprüfung als Pflicht erkennen",
|
||||||
|
"GEG 2024 Heizungstausch-Implikationen"
|
||||||
|
],
|
||||||
|
"topics": ["DIN 1988-200", "AVBWasserV", "GEG 2024", "Notdienst"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "SHK (Sanitär-Heizung-Klima)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "elektro",
|
||||||
|
"title": "Elektro",
|
||||||
|
"objectives": [
|
||||||
|
"Stundensatz 68-105 EUR/h einordnen",
|
||||||
|
"DIN VDE 0100-600 Messung + Protokoll als Pflicht erkennen",
|
||||||
|
"DGUV V3 wiederkehrende Prüfung als Auftragsquelle"
|
||||||
|
],
|
||||||
|
"topics": ["DIN VDE 0100", "DGUV V3", "TAB", "Wallbox §14a EnWG"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Elektro"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "maler",
|
||||||
|
"title": "Maler / Stuckateur",
|
||||||
|
"objectives": [
|
||||||
|
"Stundensatz 62-95 EUR/h einordnen",
|
||||||
|
"Untergrundprüfung nach DIN 18363 als Pflicht erkennen",
|
||||||
|
"Bedenkenanzeige nach §4 Abs. 3 VOB/B sicher anwenden"
|
||||||
|
],
|
||||||
|
"topics": ["DIN 18363", "Bedenkenanzeige", "Untergrund", "Tapeten-Rapport"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Maler / Stuckateur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "tischler",
|
||||||
|
"title": "Tischler / Schreiner",
|
||||||
|
"objectives": [
|
||||||
|
"Stundensatz 63-100 EUR/h einordnen",
|
||||||
|
"Werkstattzeit vs Montagezeit unterscheiden",
|
||||||
|
"Aufmaß-Toleranz vor Werkstatt-Fertigung beachten"
|
||||||
|
],
|
||||||
|
"topics": ["DIN 18355", "Maßanfertigung", "Aufmaß", "Beschläge"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Tischler / Schreiner"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gewerks-vergleich",
|
||||||
|
"title": "Gewerks-Vergleich Stundensatz",
|
||||||
|
"objectives": [
|
||||||
|
"Tabelle Geselle/Meister-Sätze 2025-26 kennen",
|
||||||
|
"Regionale Spreizung beachten",
|
||||||
|
"Marktpreis ungleich kostendeckender Preis"
|
||||||
|
],
|
||||||
|
"topics": ["Marktvergleich", "Region", "DACH 2025-26"],
|
||||||
|
"difficulty": "einfach",
|
||||||
|
"source_heading": "Aktuelle Marktsätze 2025/2026"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "nachkalkulation",
|
||||||
|
"title": "4 · Nachkalkulation & Pareto",
|
||||||
|
"short": "Aus jedem Auftrag systematisch lernen",
|
||||||
|
"icon": "trending-up",
|
||||||
|
"color": "#22c55e",
|
||||||
|
"description": "Soll-Ist-Vergleich pro Auftrag: Stunden-Differenz, Material-Mehrverbrauch, Marge real ermitteln. Pareto-Analyse identifiziert die 3-5 wiederkehrenden Margen-Killer. Soll-Stunden-Faktor (SSF) als Profi-Kennzahl.",
|
||||||
|
"source_md": "06-nachkalkulation.md",
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "soll-ist-vergleich",
|
||||||
|
"title": "Soll-Ist-Vergleich Stunden + Material",
|
||||||
|
"objectives": [
|
||||||
|
"Stunden-Differenz pro Position erfassen",
|
||||||
|
"Material EK Soll vs Ist vergleichen (>10% = Alarm)",
|
||||||
|
"Marge in EUR und % differenziert ausweisen"
|
||||||
|
],
|
||||||
|
"topics": ["Soll-Werte", "Ist-Werte", "Differenz-Analyse"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Die 4 Nachkalkulations-Dimensionen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "pareto-margenanalyse",
|
||||||
|
"title": "Pareto-Analyse Margen-Killer",
|
||||||
|
"objectives": [
|
||||||
|
"10 schlechteste Aufträge pro Quartal clustern",
|
||||||
|
"3-5 wiederkehrende Posten identifizieren",
|
||||||
|
"Systematische Kalkulationslücke schließen"
|
||||||
|
],
|
||||||
|
"topics": ["80/20", "Cluster", "wiederkehrende Posten"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Pareto-Analyse — die 80/20-Regel der Margen-Killer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ssf-kennzahl",
|
||||||
|
"title": "Soll-Stunden-Faktor (SSF)",
|
||||||
|
"objectives": [
|
||||||
|
"SSF berechnen: Ist-Stunden / Soll-Stunden",
|
||||||
|
"Zielkorridor 1,05-1,15 als guter Wert",
|
||||||
|
">1,30 als Anlass für Stunden-Sätze-Neuerhebung"
|
||||||
|
],
|
||||||
|
"topics": ["SSF", "Lerngeschwindigkeit", "Kalkulations-Reife"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Soll-Stunden-Faktor (SSF)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cluster-analyse",
|
||||||
|
"title": "Auftragstyp-Cluster analysieren",
|
||||||
|
"objectives": [
|
||||||
|
"Aufträge nach Typ aggregieren (Bad-Sanierung, Notdienst, etc.)",
|
||||||
|
"Cluster mit chronisch niedriger Marge erkennen",
|
||||||
|
"Strategische Entscheidung Kalkulation anpassen vs Cluster abstoßen"
|
||||||
|
],
|
||||||
|
"topics": ["Cluster", "Auftragstyp", "Marge-Trend"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Nachkalkulation pro Gewerk-/Auftragstyp clustern"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "fallen",
|
||||||
|
"title": "5 · Typische Fallen & Verträge",
|
||||||
|
"short": "12 Kalkulationsfallen + VOB/B vs BGB",
|
||||||
|
"icon": "alert-triangle",
|
||||||
|
"color": "#ef4444",
|
||||||
|
"description": "Die 12 häufigsten Kalkulationsfallen aller Gewerke plus Vertragsformen: BGB-Werkvertrag (5J Gewährleistung Bau, 2J andere) vs VOB/B (4J Bau, neue 2J nach Mängelbeseitigung). Eventualpositionen, Stundenlohnarbeiten, Bedenkenanzeige.",
|
||||||
|
"source_md": "05-typische-kalkulationsfallen.md",
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "fallen-allgemein",
|
||||||
|
"title": "Allgemeine Kalkulationsfallen",
|
||||||
|
"objectives": [
|
||||||
|
"Lohnnebenkosten zu niedrig (Faktor 1,3 vs 1,78)",
|
||||||
|
"Wagniszuschlag fehlt komplett",
|
||||||
|
"Skonto eingerechnet aber nicht gezogen"
|
||||||
|
],
|
||||||
|
"topics": ["Lohnnebenkosten", "Wagnis", "Skonto", "Gerüst", "Anfahrt"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Allgemein (alle Gewerke)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "fallen-gewerk",
|
||||||
|
"title": "Gewerks-spezifische Fallen",
|
||||||
|
"objectives": [
|
||||||
|
"SHK: Spülung/Druckprüfung im Stundenlohn versteckt",
|
||||||
|
"Elektro: Abschlussmessung nicht extra ausgewiesen",
|
||||||
|
"Maler: Untergrundprüfung im m²-Preis versteckt",
|
||||||
|
"Tischler: Aufmaß-Toleranz nicht eingerechnet"
|
||||||
|
],
|
||||||
|
"topics": ["Spülung", "DGUV V3", "Untergrund", "Aufmaß-Toleranz"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "SHK-spezifisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vob-bgb",
|
||||||
|
"title": "VOB/B vs BGB-Werkvertrag",
|
||||||
|
"objectives": [
|
||||||
|
"Geltung: VOB nur wenn vereinbart",
|
||||||
|
"Gewährleistung: 5J BGB Bau / 4J VOB Bau / 2J andere",
|
||||||
|
"Frist-Lauf: VOB neue 2J nach Mängelbeseitigung"
|
||||||
|
],
|
||||||
|
"topics": ["BGB §631", "VOB/B §13", "Gewährleistung", "Mängelrüge"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "VOB/B vs. BGB — wann was?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vob-c-praxis",
|
||||||
|
"title": "VOB/C — Aufmaß + Eventualpositionen",
|
||||||
|
"objectives": [
|
||||||
|
"DIN 18299 Allgemeine Regelungen kennen",
|
||||||
|
"OZ-Nummern hierarchisch aufbauen",
|
||||||
|
"Eventualpositionen bei unklaren Mengen sinnvoll einsetzen",
|
||||||
|
"Stundenlohnarbeiten nach §15 VOB/B vorab vereinbaren"
|
||||||
|
],
|
||||||
|
"topics": ["DIN 18299", "OZ-Nummern", "Eventualpositionen", "Stundenlohnarbeiten"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "DIN 18299 — die wichtigsten 5 Abschnitte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "preisdruecker",
|
||||||
|
"title": "Preisdrücker-Kunden + Notdienst-Tarife",
|
||||||
|
"objectives": [
|
||||||
|
"Wert statt Rabatt anbieten",
|
||||||
|
"Roter Stoppschild-Satz formulieren",
|
||||||
|
"Notdienst mit 100-150% Zuschlag korrekt kalkulieren"
|
||||||
|
],
|
||||||
|
"topics": ["Preisdrücker", "Skonto-Geste", "Notdienst-Zuschlag"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Wie reagiere ich auf Preisdrücker-Kunden?"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"badges": [
|
||||||
|
{"id": "erste_kalkulation", "title": "Erste Kalkulation", "icon": "calculator", "description": "1. Quiz im Stundensatz-Modul erfolgreich."},
|
||||||
|
{"id": "gewerks_meister", "title": "Gewerks-Meister", "icon": "hammer", "description": "5 Quiz im Gewerke-Spezifika-Modul korrekt."},
|
||||||
|
{"id": "marge_optimierer", "title": "Marge-Optimierer", "icon": "trending-up", "description": "3 Quiz im Nachkalkulations-Modul korrekt."},
|
||||||
|
{"id": "fallen_kenner", "title": "Fallen-Kenner", "icon": "alert-triangle", "description": "5 Quiz im Fallen-Modul korrekt — kennt die typischen Margen-Killer."},
|
||||||
|
{"id": "libra_meister", "title": "LIBRA-Meister", "icon": "crown", "description": "Alle 5 Curricula mit >=80% abgeschlossen."},
|
||||||
|
{"id": "streak_7", "title": "Wochenstreak", "icon": "flame", "description": "7 Tage in Folge aktiv gewesen."},
|
||||||
|
{"id": "night_owl", "title": "Nachteule", "icon": "moon", "description": "Nach 22 Uhr gelernt."},
|
||||||
|
{"id": "early_bird", "title": "Frühaufsteher", "icon": "sun", "description": "Vor 7 Uhr gelernt."}
|
||||||
|
],
|
||||||
|
"levels": [
|
||||||
|
{"min": 0, "title": "Lehrling"},
|
||||||
|
{"min": 50, "title": "Geselle"},
|
||||||
|
{"min": 200, "title": "Vorarbeiter"},
|
||||||
|
{"min": 500, "title": "Meister"},
|
||||||
|
{"min": 1250, "title": "Betriebsleiter"},
|
||||||
|
{"min": 2500, "title": "Inhaber"},
|
||||||
|
{"min": 5000, "title": "Handwerks-Unternehmer"}
|
||||||
|
]
|
||||||
|
}
|
||||||
4
src/levels-fallback.js
Normal file
4
src/levels-fallback.js
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
{ min: 0, title: 'Lehrling' }, { min: 50, title: 'Geselle' },
|
||||||
|
{ min: 200, title: 'Vorarbeiter' }, { min: 500, title: 'Meister' },
|
||||||
|
{ min: 1250, title: 'Betriebsleiter' }, { min: 2500, title: 'Inhaber' },
|
||||||
|
{ min: 5000, title: 'Handwerks-Unternehmer' }
|
||||||
29
src/welcome.html
Normal file
29
src/welcome.html
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<h2>Willkommen bei LIBRA!</h2>
|
||||||
|
<p>Hi, ich bin LIBRA. Ich rette deine <strong>Marge</strong>, bevor du das Angebot rausgibst. Sag mir Gewerk und Auftragstyp — ich rechne mit dir durch: <strong>Stundensatz</strong>, Material, Fahrtzeit, Wagniszuschlag. Plus: nach jedem Auftrag <strong>Nachkalkulation</strong>, lerne aus den 5 Posten, die immer Marge fressen. Alles im deutschen Bunker — keine Daten verlassen deinen Betrieb.</p>
|
||||||
|
<div class="mode-grid">
|
||||||
|
<button class="mode-card" data-goto="chat">
|
||||||
|
<strong>Chat</strong>
|
||||||
|
<span>Frag mich zu Stundensatz, Material, VOB/C, Nachkalkulation.</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-card" data-goto="quiz">
|
||||||
|
<strong>Quiz</strong>
|
||||||
|
<span>Szenario-Fragen aus Baustelle & Büro, mit XP.</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-card" data-goto="flash">
|
||||||
|
<strong>Flashcards</strong>
|
||||||
|
<span>Formeln, Aufschläge, Gewerks-Spezifika — mit Spaced-Repetition.</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-card" data-goto="progress">
|
||||||
|
<strong>Fortschritt</strong>
|
||||||
|
<span>XP, Streaks, Badges, Level vom Lehrling zum Inhaber.</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-card" data-goto="curriculum">
|
||||||
|
<strong>Gewerke</strong>
|
||||||
|
<span>5 Curricula / 23 Module: Stundensatz, Material, Gewerks-Spezifika, Nachkalkulation, Verträge.</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-card" data-prompt="CALC_REQUEST: Stundensatz für [Gewerk], [Lohnnebenkosten %], [Gemeinkosten %], [Wagnis-/Gewinn-Aufschlag %]">
|
||||||
|
<strong>Stundensatz-Rechner</strong>
|
||||||
|
<span><code>CALC_REQUEST</code> + Gewerk/Aufschläge → Stundensatz mit Aufschlüsselung als Karte.</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p style="font-size:.82rem;color:var(--text-mute)">In 3 Sätzen: Chat zum Verstehen → Quiz zum Testen → Flashcards zum Merken. Fortschritt zeigt dir, wo du stehst; die Gewerke-Bibliothek gibt dir 5 kuratierte Module für SHK, Elektro, Maler und Tischler.</p>
|
||||||
1747
www/app.js
Normal file
1747
www/app.js
Normal file
File diff suppressed because it is too large
Load diff
358
www/curricula.json
Normal file
358
www/curricula.json
Normal file
|
|
@ -0,0 +1,358 @@
|
||||||
|
{
|
||||||
|
"version": "2026-04-25",
|
||||||
|
"updated": "2026-04-25",
|
||||||
|
"curricula": [
|
||||||
|
{
|
||||||
|
"id": "stundensatz",
|
||||||
|
"title": "1 · Stundensatz & Lohnnebenkosten",
|
||||||
|
"short": "Vollkostendeckender SVS bilden",
|
||||||
|
"icon": "clock",
|
||||||
|
"color": "#d97706",
|
||||||
|
"description": "Vom Bruttolohn zum vollkostendeckenden Stundenverrechnungssatz: Lohnnebenkosten korrekt aufschlagen, produktive Stunden realistisch ansetzen, Gemeinkosten verteilen, Wagnis- und Gewinnzuschlag.",
|
||||||
|
"source_md": "01-stundensatz-bilden.md",
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "lohnnebenkosten",
|
||||||
|
"title": "Lohnnebenkosten korrekt aufschlagen",
|
||||||
|
"objectives": [
|
||||||
|
"Standard-Aufschlag 75-80% auf Brutto kennen",
|
||||||
|
"SOKA-Bau-Spezifikum verstehen (Faktor bis 105%)",
|
||||||
|
"Berufsgenossenschaft je Gewerk einordnen"
|
||||||
|
],
|
||||||
|
"topics": ["Sozialabgaben", "Urlaub", "Krankheit", "BG", "SOKA-Bau"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Schritt 2 — Lohnnebenkosten aufschlagen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "produktive-stunden",
|
||||||
|
"title": "Produktive Stunden realistisch",
|
||||||
|
"objectives": [
|
||||||
|
"1.400-1.650 h/Jahr als Realität akzeptieren",
|
||||||
|
"Abzüge sauber rechnen (Urlaub, Krankheit, Schulung, Werkstatt)",
|
||||||
|
"Wirkung von 200 h Differenz auf SVS verstehen"
|
||||||
|
],
|
||||||
|
"topics": ["Produktivstunden", "Auslastung", "1.436-h-Beispiel"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Schritt 3 — Produktive Stunden ermitteln"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gemeinkosten",
|
||||||
|
"title": "Gemeinkosten verteilen",
|
||||||
|
"objectives": [
|
||||||
|
"Werkstatt + Fuhrpark + Verwaltung + Versicherungen + Marketing erfassen",
|
||||||
|
"Pro produktiver Stunde umlegen",
|
||||||
|
"4-Mann-Beispielrechnung durchgehen (122k €/Jahr → 28,30 €/h)"
|
||||||
|
],
|
||||||
|
"topics": ["Werkstatt", "Fuhrpark", "Verwaltung", "Umlage"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Schritt 4 — Gemeinkosten verteilen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "wagnis-gewinn",
|
||||||
|
"title": "Wagnis- und Gewinnzuschlag",
|
||||||
|
"objectives": [
|
||||||
|
"Wagniszuschlag 5-10% als Pflicht erkennen",
|
||||||
|
"Gewinnzuschlag 8-15% als Substanz-Erhalt verstehen",
|
||||||
|
"5%-Falle vermeiden (Substanzverzehr)"
|
||||||
|
],
|
||||||
|
"topics": ["Wagnis", "Gewinn", "Forderungsausfall", "Substanz"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Schritt 5 — Wagniszuschlag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "svs-formel",
|
||||||
|
"title": "SVS-Endformel + Marktvergleich",
|
||||||
|
"objectives": [
|
||||||
|
"Vollständige SVS-Formel anwenden können",
|
||||||
|
"75-Euro-Standard kritisch hinterfragen",
|
||||||
|
"Regionale Spreizung kennen (Berlin/München vs Sachsen/Thüringen)"
|
||||||
|
],
|
||||||
|
"topics": ["SVS-Formel", "Marktpreis", "regionale Spreizung"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Schritt 7 — Vollständige SVS-Formel"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "material",
|
||||||
|
"title": "2 · Materialaufschlag & Skonto",
|
||||||
|
"short": "Aufschlag, Marge, Verschnitt, Skonto-Strategie",
|
||||||
|
"icon": "package",
|
||||||
|
"color": "#f59e0b",
|
||||||
|
"description": "Materialaufschlag richtig kalkulieren: Aufschlag vs. Marge, Skonto als Margen-Killer, Verschnitt-Reserve, Sondermaterial-Beschaffungspauschale, Lieferanten-Lock-in vermeiden.",
|
||||||
|
"source_md": "02-materialaufschlag.md",
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "aufschlag-grundlagen",
|
||||||
|
"title": "Was deckt der Materialaufschlag",
|
||||||
|
"objectives": [
|
||||||
|
"6 Kostenblöcke des Aufschlags benennen",
|
||||||
|
"Übliche Aufschläge nach Materialklasse kennen",
|
||||||
|
"Faustregel 25% auf EK als Standard-Mitte"
|
||||||
|
],
|
||||||
|
"topics": ["Bestellung", "Transport", "Lager", "Verschnitt", "Vorfinanzierung", "Gewährleistung"],
|
||||||
|
"difficulty": "einfach",
|
||||||
|
"source_heading": "Was deckt der Materialaufschlag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "aufschlag-vs-marge",
|
||||||
|
"title": "Aufschlag vs. Marge — kein Verwechslungsfehler",
|
||||||
|
"objectives": [
|
||||||
|
"25% Aufschlag = 20% Marge sicher umrechnen",
|
||||||
|
"Bei Lieferanten-Gespräch korrekt nachfragen",
|
||||||
|
"5%-Lücke pro 100k Material berechnen können"
|
||||||
|
],
|
||||||
|
"topics": ["Aufschlag-Formel", "Marge-Formel"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Aufschlag vs. Marge — der ewige Verwechslungsfehler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "skonto",
|
||||||
|
"title": "Skonto-Strategie",
|
||||||
|
"objectives": [
|
||||||
|
"Skonto immer in Kalkulation einrechnen",
|
||||||
|
"Skonto immer ziehen (Liquiditäts-Disziplin)",
|
||||||
|
"2% Skonto als 30-50% des Gewinns einordnen"
|
||||||
|
],
|
||||||
|
"topics": ["2/14 Tage", "Kalkulationsskonto", "Liquidität"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Skonto — der unterschätzte Margenkiller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "verschnitt",
|
||||||
|
"title": "Verschnitt-Reserve pro Material",
|
||||||
|
"objectives": [
|
||||||
|
"Materialspezifische Verschnitt-Quoten kennen",
|
||||||
|
"Verschnitt kalkulieren, nicht abrechnen",
|
||||||
|
"Tapeten-Rapport bis 25% beachten"
|
||||||
|
],
|
||||||
|
"topics": ["Kupferrohr", "Kabel", "Tapeten", "Fliesen", "Holz"],
|
||||||
|
"difficulty": "einfach",
|
||||||
|
"source_heading": "Verschnitt-Reserve"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gewerks-spezifika",
|
||||||
|
"title": "3 · Gewerke-Spezifika",
|
||||||
|
"short": "SHK / Elektro / Maler / Tischler im Detail",
|
||||||
|
"icon": "layers",
|
||||||
|
"color": "#b45309",
|
||||||
|
"description": "Pro Gewerk: typische Stundensätze, Material-Mix, Kalkulationsfallen, Rechtsrahmen (DIN VDE, DIN 1988, DIN 18363), VOB/B vs BGB, Gewährleistung 5J Bau / 2J BGB.",
|
||||||
|
"source_md": "07-rollen-spezifisch-shk-elektro-maler-tischler.md",
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "shk",
|
||||||
|
"title": "SHK — Sanitär/Heizung/Klima",
|
||||||
|
"objectives": [
|
||||||
|
"Stundensatz 75-115 EUR/h einordnen",
|
||||||
|
"DIN 1988-200 Spülung + Druckprüfung als Pflicht erkennen",
|
||||||
|
"GEG 2024 Heizungstausch-Implikationen"
|
||||||
|
],
|
||||||
|
"topics": ["DIN 1988-200", "AVBWasserV", "GEG 2024", "Notdienst"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "SHK (Sanitär-Heizung-Klima)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "elektro",
|
||||||
|
"title": "Elektro",
|
||||||
|
"objectives": [
|
||||||
|
"Stundensatz 68-105 EUR/h einordnen",
|
||||||
|
"DIN VDE 0100-600 Messung + Protokoll als Pflicht erkennen",
|
||||||
|
"DGUV V3 wiederkehrende Prüfung als Auftragsquelle"
|
||||||
|
],
|
||||||
|
"topics": ["DIN VDE 0100", "DGUV V3", "TAB", "Wallbox §14a EnWG"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Elektro"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "maler",
|
||||||
|
"title": "Maler / Stuckateur",
|
||||||
|
"objectives": [
|
||||||
|
"Stundensatz 62-95 EUR/h einordnen",
|
||||||
|
"Untergrundprüfung nach DIN 18363 als Pflicht erkennen",
|
||||||
|
"Bedenkenanzeige nach §4 Abs. 3 VOB/B sicher anwenden"
|
||||||
|
],
|
||||||
|
"topics": ["DIN 18363", "Bedenkenanzeige", "Untergrund", "Tapeten-Rapport"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Maler / Stuckateur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "tischler",
|
||||||
|
"title": "Tischler / Schreiner",
|
||||||
|
"objectives": [
|
||||||
|
"Stundensatz 63-100 EUR/h einordnen",
|
||||||
|
"Werkstattzeit vs Montagezeit unterscheiden",
|
||||||
|
"Aufmaß-Toleranz vor Werkstatt-Fertigung beachten"
|
||||||
|
],
|
||||||
|
"topics": ["DIN 18355", "Maßanfertigung", "Aufmaß", "Beschläge"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Tischler / Schreiner"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gewerks-vergleich",
|
||||||
|
"title": "Gewerks-Vergleich Stundensatz",
|
||||||
|
"objectives": [
|
||||||
|
"Tabelle Geselle/Meister-Sätze 2025-26 kennen",
|
||||||
|
"Regionale Spreizung beachten",
|
||||||
|
"Marktpreis ungleich kostendeckender Preis"
|
||||||
|
],
|
||||||
|
"topics": ["Marktvergleich", "Region", "DACH 2025-26"],
|
||||||
|
"difficulty": "einfach",
|
||||||
|
"source_heading": "Aktuelle Marktsätze 2025/2026"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "nachkalkulation",
|
||||||
|
"title": "4 · Nachkalkulation & Pareto",
|
||||||
|
"short": "Aus jedem Auftrag systematisch lernen",
|
||||||
|
"icon": "trending-up",
|
||||||
|
"color": "#22c55e",
|
||||||
|
"description": "Soll-Ist-Vergleich pro Auftrag: Stunden-Differenz, Material-Mehrverbrauch, Marge real ermitteln. Pareto-Analyse identifiziert die 3-5 wiederkehrenden Margen-Killer. Soll-Stunden-Faktor (SSF) als Profi-Kennzahl.",
|
||||||
|
"source_md": "06-nachkalkulation.md",
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "soll-ist-vergleich",
|
||||||
|
"title": "Soll-Ist-Vergleich Stunden + Material",
|
||||||
|
"objectives": [
|
||||||
|
"Stunden-Differenz pro Position erfassen",
|
||||||
|
"Material EK Soll vs Ist vergleichen (>10% = Alarm)",
|
||||||
|
"Marge in EUR und % differenziert ausweisen"
|
||||||
|
],
|
||||||
|
"topics": ["Soll-Werte", "Ist-Werte", "Differenz-Analyse"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Die 4 Nachkalkulations-Dimensionen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "pareto-margenanalyse",
|
||||||
|
"title": "Pareto-Analyse Margen-Killer",
|
||||||
|
"objectives": [
|
||||||
|
"10 schlechteste Aufträge pro Quartal clustern",
|
||||||
|
"3-5 wiederkehrende Posten identifizieren",
|
||||||
|
"Systematische Kalkulationslücke schließen"
|
||||||
|
],
|
||||||
|
"topics": ["80/20", "Cluster", "wiederkehrende Posten"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Pareto-Analyse — die 80/20-Regel der Margen-Killer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ssf-kennzahl",
|
||||||
|
"title": "Soll-Stunden-Faktor (SSF)",
|
||||||
|
"objectives": [
|
||||||
|
"SSF berechnen: Ist-Stunden / Soll-Stunden",
|
||||||
|
"Zielkorridor 1,05-1,15 als guter Wert",
|
||||||
|
">1,30 als Anlass für Stunden-Sätze-Neuerhebung"
|
||||||
|
],
|
||||||
|
"topics": ["SSF", "Lerngeschwindigkeit", "Kalkulations-Reife"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Soll-Stunden-Faktor (SSF)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cluster-analyse",
|
||||||
|
"title": "Auftragstyp-Cluster analysieren",
|
||||||
|
"objectives": [
|
||||||
|
"Aufträge nach Typ aggregieren (Bad-Sanierung, Notdienst, etc.)",
|
||||||
|
"Cluster mit chronisch niedriger Marge erkennen",
|
||||||
|
"Strategische Entscheidung Kalkulation anpassen vs Cluster abstoßen"
|
||||||
|
],
|
||||||
|
"topics": ["Cluster", "Auftragstyp", "Marge-Trend"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "Nachkalkulation pro Gewerk-/Auftragstyp clustern"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "fallen",
|
||||||
|
"title": "5 · Typische Fallen & Verträge",
|
||||||
|
"short": "12 Kalkulationsfallen + VOB/B vs BGB",
|
||||||
|
"icon": "alert-triangle",
|
||||||
|
"color": "#ef4444",
|
||||||
|
"description": "Die 12 häufigsten Kalkulationsfallen aller Gewerke plus Vertragsformen: BGB-Werkvertrag (5J Gewährleistung Bau, 2J andere) vs VOB/B (4J Bau, neue 2J nach Mängelbeseitigung). Eventualpositionen, Stundenlohnarbeiten, Bedenkenanzeige.",
|
||||||
|
"source_md": "05-typische-kalkulationsfallen.md",
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "fallen-allgemein",
|
||||||
|
"title": "Allgemeine Kalkulationsfallen",
|
||||||
|
"objectives": [
|
||||||
|
"Lohnnebenkosten zu niedrig (Faktor 1,3 vs 1,78)",
|
||||||
|
"Wagniszuschlag fehlt komplett",
|
||||||
|
"Skonto eingerechnet aber nicht gezogen"
|
||||||
|
],
|
||||||
|
"topics": ["Lohnnebenkosten", "Wagnis", "Skonto", "Gerüst", "Anfahrt"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Allgemein (alle Gewerke)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "fallen-gewerk",
|
||||||
|
"title": "Gewerks-spezifische Fallen",
|
||||||
|
"objectives": [
|
||||||
|
"SHK: Spülung/Druckprüfung im Stundenlohn versteckt",
|
||||||
|
"Elektro: Abschlussmessung nicht extra ausgewiesen",
|
||||||
|
"Maler: Untergrundprüfung im m²-Preis versteckt",
|
||||||
|
"Tischler: Aufmaß-Toleranz nicht eingerechnet"
|
||||||
|
],
|
||||||
|
"topics": ["Spülung", "DGUV V3", "Untergrund", "Aufmaß-Toleranz"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "SHK-spezifisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vob-bgb",
|
||||||
|
"title": "VOB/B vs BGB-Werkvertrag",
|
||||||
|
"objectives": [
|
||||||
|
"Geltung: VOB nur wenn vereinbart",
|
||||||
|
"Gewährleistung: 5J BGB Bau / 4J VOB Bau / 2J andere",
|
||||||
|
"Frist-Lauf: VOB neue 2J nach Mängelbeseitigung"
|
||||||
|
],
|
||||||
|
"topics": ["BGB §631", "VOB/B §13", "Gewährleistung", "Mängelrüge"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "VOB/B vs. BGB — wann was?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vob-c-praxis",
|
||||||
|
"title": "VOB/C — Aufmaß + Eventualpositionen",
|
||||||
|
"objectives": [
|
||||||
|
"DIN 18299 Allgemeine Regelungen kennen",
|
||||||
|
"OZ-Nummern hierarchisch aufbauen",
|
||||||
|
"Eventualpositionen bei unklaren Mengen sinnvoll einsetzen",
|
||||||
|
"Stundenlohnarbeiten nach §15 VOB/B vorab vereinbaren"
|
||||||
|
],
|
||||||
|
"topics": ["DIN 18299", "OZ-Nummern", "Eventualpositionen", "Stundenlohnarbeiten"],
|
||||||
|
"difficulty": "schwer",
|
||||||
|
"source_heading": "DIN 18299 — die wichtigsten 5 Abschnitte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "preisdruecker",
|
||||||
|
"title": "Preisdrücker-Kunden + Notdienst-Tarife",
|
||||||
|
"objectives": [
|
||||||
|
"Wert statt Rabatt anbieten",
|
||||||
|
"Roter Stoppschild-Satz formulieren",
|
||||||
|
"Notdienst mit 100-150% Zuschlag korrekt kalkulieren"
|
||||||
|
],
|
||||||
|
"topics": ["Preisdrücker", "Skonto-Geste", "Notdienst-Zuschlag"],
|
||||||
|
"difficulty": "mittel",
|
||||||
|
"source_heading": "Wie reagiere ich auf Preisdrücker-Kunden?"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"badges": [
|
||||||
|
{"id": "erste_kalkulation", "title": "Erste Kalkulation", "icon": "calculator", "description": "1. Quiz im Stundensatz-Modul erfolgreich."},
|
||||||
|
{"id": "gewerks_meister", "title": "Gewerks-Meister", "icon": "hammer", "description": "5 Quiz im Gewerke-Spezifika-Modul korrekt."},
|
||||||
|
{"id": "marge_optimierer", "title": "Marge-Optimierer", "icon": "trending-up", "description": "3 Quiz im Nachkalkulations-Modul korrekt."},
|
||||||
|
{"id": "fallen_kenner", "title": "Fallen-Kenner", "icon": "alert-triangle", "description": "5 Quiz im Fallen-Modul korrekt — kennt die typischen Margen-Killer."},
|
||||||
|
{"id": "libra_meister", "title": "LIBRA-Meister", "icon": "crown", "description": "Alle 5 Curricula mit >=80% abgeschlossen."},
|
||||||
|
{"id": "streak_7", "title": "Wochenstreak", "icon": "flame", "description": "7 Tage in Folge aktiv gewesen."},
|
||||||
|
{"id": "night_owl", "title": "Nachteule", "icon": "moon", "description": "Nach 22 Uhr gelernt."},
|
||||||
|
{"id": "early_bird", "title": "Frühaufsteher", "icon": "sun", "description": "Vor 7 Uhr gelernt."}
|
||||||
|
],
|
||||||
|
"levels": [
|
||||||
|
{"min": 0, "title": "Lehrling"},
|
||||||
|
{"min": 50, "title": "Geselle"},
|
||||||
|
{"min": 200, "title": "Vorarbeiter"},
|
||||||
|
{"min": 500, "title": "Meister"},
|
||||||
|
{"min": 1250, "title": "Betriebsleiter"},
|
||||||
|
{"min": 2500, "title": "Inhaber"},
|
||||||
|
{"min": 5000, "title": "Handwerks-Unternehmer"}
|
||||||
|
]
|
||||||
|
}
|
||||||
125
www/index.html
Normal file
125
www/index.html
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>LIBRA · Dein Handwerks-Kalkulationscoach</title>
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
||||||
|
<meta name="theme-color" content="#0a0a0f">
|
||||||
|
<meta name="description" content="LIBRA — der Kalkulations-Sparringspartner für SHK/Elektro/Maler/Tischler. Stundensätze, Materialaufschläge, Nachkalkulation. Im deutschen Bunker.">
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
<script>window.__LIBRA_KEY__ = 'qb_pz7hy9gkl1du';</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="app" role="application" aria-label="LIBRA Handwerks-Kalkulationscoach">
|
||||||
|
|
||||||
|
<header class="topbar">
|
||||||
|
<div class="brand">
|
||||||
|
<span class="brand-icon" aria-hidden="true">L</span>
|
||||||
|
<span>LIBRA <small>Kalkulationscoach</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">
|
||||||
|
Karten
|
||||||
|
<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">
|
||||||
|
Gewerke
|
||||||
|
<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>Willkommen bei LIBRA!</h2>
|
||||||
|
<p>Hi, ich bin LIBRA. Ich rette deine <strong>Marge</strong>, bevor du das Angebot rausgibst. Sag mir Gewerk und Auftragstyp — ich rechne mit dir durch: <strong>Stundensatz</strong>, Material, Fahrtzeit, Wagniszuschlag. Plus: nach jedem Auftrag <strong>Nachkalkulation</strong>, lerne aus den 5 Posten, die immer Marge fressen. Alles im deutschen Bunker — keine Daten verlassen deinen Betrieb.</p>
|
||||||
|
<div class="mode-grid">
|
||||||
|
<button class="mode-card" data-goto="chat">
|
||||||
|
<strong>Chat</strong>
|
||||||
|
<span>Frag mich zu Stundensatz, Material, VOB/C, Nachkalkulation.</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-card" data-goto="quiz">
|
||||||
|
<strong>Quiz</strong>
|
||||||
|
<span>Szenario-Fragen aus Baustelle & Büro, mit XP.</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-card" data-goto="flash">
|
||||||
|
<strong>Flashcards</strong>
|
||||||
|
<span>Formeln, Aufschläge, Gewerks-Spezifika — mit Spaced-Repetition.</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-card" data-goto="progress">
|
||||||
|
<strong>Fortschritt</strong>
|
||||||
|
<span>XP, Streaks, Badges, Level vom Lehrling zum Inhaber.</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-card" data-goto="curriculum">
|
||||||
|
<strong>Gewerke</strong>
|
||||||
|
<span>5 Curricula / 23 Module: Stundensatz, Material, Gewerks-Spezifika, Nachkalkulation, Verträge.</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-card" data-prompt="CALC_REQUEST: Stundensatz für [Gewerk], [Lohnnebenkosten %], [Gemeinkosten %], [Wagnis-/Gewinn-Aufschlag %]">
|
||||||
|
<strong>Stundensatz-Rechner</strong>
|
||||||
|
<span><code>CALC_REQUEST</code> + Gewerk/Aufschläge → Stundensatz mit Aufschlüsselung als Karte.</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p style="font-size:.82rem;color:var(--text-mute)">In 3 Sätzen: Chat zum Verstehen → Quiz zum Testen → Flashcards zum Merken. Fortschritt zeigt dir, wo du stehst; die Gewerke-Bibliothek gibt dir 5 kuratierte Module für SHK, Elektro, Maler und Tischler.</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 LIBRA — 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> · 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
1038
www/styles.css
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue