Erste Etappe des v3-Umbaus. Bewusst ohne jede Architektur-Aenderung: nur Entruempeln, damit der Rest des Umbaus auf einem messbar leichten Stand aufsetzt. Gemessen (vorher -> nachher): dist gesamt 27 375 720 B -> 1 477 852 B (-94,6 %) Dateien in dist 135 -> 35 Start-Chunk gzip 220 278 B -> 110 571 B (-49,8 %) CSS gzip 31 577 B -> 15 121 B (-52,1 %) Schrift-Dateien 112 -> 11 (WOFF 1: 0) Vier Eingriffe: 1) avatar.vrm (24,5 MB) entfernt. Lag in public/ und dist/, wurde von KEINER Zeile des Repos referenziert — der Renderer Avatar3D.tsx war schon vorher verschwunden. War 89,5 % der Nutzlast, die auf die Box ging. Damit fallen auch die .gitignore-Sonderregel und der Direkt-Deploy-Schritt weg. DISASTER_RECOVERY.md §3·D ehrlich auf "ausgebaut" gesetzt (7 Stellen). 2) Schriften: die 11 @fontsource-Sammelimporte zogen ALLE Subsets (latin-ext, griechisch, kyrillisch) und je eine WOFF-1-Fassung mit — 112 Dateien, 1,58 MB, davon 902 kB WOFF 1, das kein Browser dieser App je abruft. Jetzt stehen die @font-face-Regeln direkt in index.css: nur latin, nur WOFF 2, nur die Schnitte, die per grep ueber die font-*-Klassen wirklich belegt sind. Nebenbei behoben: JetBrains Mono 600/700 fehlten komplett — die 19 Stellen mit `font-mono font-bold/semibold` wurden vom Browser synthetisch fettgerechnet. Jetzt echte Schnitte; bei Monospace ist die Laufweite gleich, kein Layout-Versatz. 3) Recharts aus dem Startbuendel. Das Cockpit ist die Startseite und laedt daher NICHT lazy; ueber SystemStatusCard/TokenPerformanceCard zog es Recharts samt d3 in index-*.js. LiveAreaChart ist jetzt eine Lazy-Huelle (Suspense mit hoehengleichem Platzhalter, damit nichts springt), die Recharts-Umsetzung liegt in LiveAreaChartImpl.tsx und kommt als eigener Chunk nach (105 kB gzip). 4) index.css: height 100dvh mit 100% als Rueckfall. Auf Mobilbrowsern mit einfahrender Adressleiste ist 100 % nicht die sichtbare Hoehe. Dazu ein Buendel-Budget in beiden Ampel-Dateien (.gitea/ = MC2-Fassung, deploy/ = universelle Vorlage): Start-Chunk und dist-Gesamtgroesse werden am FRISCHEN Build im Runner gemessen. Bewusst kein Vergleich mit dem committeten dist — der waere ueber Node-Versionen hinweg flatterhaft und wuerde dauerhaft rot leuchten, was das Signal zerstoert. Verifiziert gegen die Box (Frontend-Dev mit MC_API_TARGET=192.168.178.151:9001): Cockpit rendert mit Live-Daten, keine Konsolenfehler, alle 11 Schriftschnitte registriert, LiveAreaChartImpl + recharts laden nachweislich als Nachlade-Chunk. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
89 lines
4.2 KiB
YAML
89 lines
4.2 KiB
YAML
# Universelle CI-Ampel — wird bei der Repo-Anlage automatisch eingepflanzt
|
||
# (gitea-repo-create.sh, Wasserdicht-Runde 22.07.2026) und läuft auf dem
|
||
# Gitea-Actions-Runner (arcane-VM).
|
||
# GRUNDSATZ: Rot ist ein Ergebnis („nicht bewiesen"), kein Ärgernis.
|
||
# • Reines Doku-Repo (noch kein Code) → GRÜN mit Vermerk.
|
||
# • Code ohne Tests → ROT. Tests sind Pflicht, kein Deko.
|
||
# Der Workflow erkennt selbst, was das Projekt ist (Python / Node / beides).
|
||
name: Ampel
|
||
on: [push, pull_request]
|
||
|
||
jobs:
|
||
ampel:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Ampel — erkennt Projekt-Typ selbst und prüft entsprechend
|
||
shell: bash
|
||
run: |
|
||
# Der Runner startet bash mit -e — das schalten wir ab: die Ampel wertet
|
||
# JEDEN Fehler selbst (rot=1) und liefert am Ende EIN Klartext-Urteil.
|
||
# (Lehre Lauf #5: ungeschütztes pytest unter -e schnitt den Bericht ab.)
|
||
set -u +e
|
||
rot=0
|
||
py_datei=$(find . -name '*.py' -not -path './.git/*' -not -path '*/node_modules/*' -print -quit)
|
||
pkg_dateien=$(find . -name package.json -not -path '*/node_modules/*' -not -path './.git/*')
|
||
|
||
if [ -z "$py_datei" ] && [ -z "$pkg_dateien" ]; then
|
||
echo "✅ Doku-Repo (noch kein Code) — Ampel GRÜN mit Vermerk."
|
||
exit 0
|
||
fi
|
||
|
||
if [ -n "$py_datei" ]; then
|
||
echo "== Python erkannt =="
|
||
{ python3 -m venv /tmp/ampel-venv && . /tmp/ampel-venv/bin/activate; } || { echo "❌ Python-Setup kaputt (venv)"; exit 1; }
|
||
pip install -q ruff pytest || { echo "❌ Werkzeug-Installation kaputt"; exit 1; }
|
||
echo "-- Ruff (Linter: toter Code, kaputte Imports, Schlampereien)"
|
||
ruff check . || rot=1
|
||
echo "-- Abhängigkeiten installierbar? (halluzinierte Pakete fliegen hier auf)"
|
||
while IFS= read -r req; do
|
||
[ -n "$req" ] || continue
|
||
pip install -q -r "$req" || { echo "❌ $req nicht installierbar"; rot=1; }
|
||
done < <(find . -name 'requirements*.txt' -not -path '*/node_modules/*' -not -path './.git/*')
|
||
echo "-- Importierbar? (kaputte Modul-Struktur fliegt hier auf)"
|
||
python -m compileall -q . || rot=1
|
||
echo "-- Pytest (keine Tests gefunden = ROT)"
|
||
ec=0; pytest -q || ec=$?
|
||
if [ $ec -eq 5 ]; then
|
||
echo "❌ KEINE TESTS GEFUNDEN — Tests sind Pflicht, kein Deko (AGENTS.md)."
|
||
rot=1
|
||
elif [ $ec -ne 0 ]; then
|
||
rot=1
|
||
fi
|
||
fi
|
||
|
||
if [ -n "$pkg_dateien" ]; then
|
||
echo "== Node/TypeScript erkannt =="
|
||
while IFS= read -r pkg; do
|
||
[ -n "$pkg" ] || continue
|
||
d=$(dirname "$pkg")
|
||
echo "-- $d"
|
||
if [ ! -f "$d/package-lock.json" ]; then
|
||
echo "❌ $d: kein package-lock.json — Build nicht reproduzierbar."
|
||
echo " Fix: dort 'npm install --package-lock-only' ausführen und committen."
|
||
rot=1; continue
|
||
fi
|
||
(cd "$d" && npm ci --no-audit --no-fund) || { rot=1; continue; }
|
||
if grep -q '"build"' "$pkg"; then (cd "$d" && npm run build) || rot=1; fi
|
||
if grep -q '"test"' "$pkg"; then (cd "$d" && npm test --silent) || rot=1; fi
|
||
|
||
# Buendel-Budget: das Start-Chunk ist, was der Nutzer VOR dem ersten Bild laedt.
|
||
# Ohne Deckel waechst es unbemerkt zurueck (eine eifrig geladene Diagramm-Lib
|
||
# reicht). Gemessen wird der frische Build, nicht das committete dist.
|
||
if [ -d "$d/dist/assets" ]; then
|
||
haupt=$(ls "$d"/dist/assets/index-*.js 2>/dev/null | head -1)
|
||
if [ -n "$haupt" ]; then
|
||
gz=$(gzip -c "$haupt" | wc -c)
|
||
echo "-- Start-Chunk: $gz B gzip (Budget 200000)"
|
||
[ "$gz" -gt 200000 ] && { echo "❌ Start-Buendel ueber Budget — hinter lazy() legen."; rot=1; }
|
||
fi
|
||
fi
|
||
done <<< "$pkg_dateien"
|
||
fi
|
||
|
||
if [ $rot -ne 0 ]; then
|
||
echo "❌ AMPEL ROT — nichts heißt ‚fertig', solange das rot ist."
|
||
fi
|
||
exit $rot
|