You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
Samuel Zielke 0a7b27e4f2
Erste Version
1 week ago
apps-script Erste Version 1 week ago
server Erste Version 1 week ago
web Erste Version 1 week ago
.gitignore Erste Version 1 week ago
README.md Erste Version 1 week ago
install.sh Erste Version 1 week ago

README.md

Monitor-Check

Bildschirme, Lautsprecher und Übersetzungsanlagen vor Ort per Handy erfassen und prüfen.

Bei Veranstaltungen mit vielen Monitoren, z. B. in Foyers, Nebenräumen oder Übertragungssälen, muss vorher jedes Gerät einmal geprüft werden: Kommt Ton? Kommt Bild? Läuft die richtige Sprache? Monitor-Check macht daraus eine kleine Web-App fürs Handy. Ihr geht von Gerät zu Gerät, macht ein Foto, tippt drei Mal auf JA / NEIN / n.A., und die Übersicht zeigt sofort, was funktioniert und wo jemand nachsehen muss.

Handy (Browser)
   ├── Foto  ──────────────► dein Server (Node)  ──► /uploads/…jpg
   └── Daten ──────────────► Apps-Script Web-App ──► Google Tabelle

Die Daten liegen in einer Google Tabelle, die ihr selbst besitzt. Dort könnt ihr filtern, drucken oder teilen. Die Oberfläche und die Fotos liegen auf eurem eigenen Server. Im Repo sind keine Zugangsdaten enthalten: Token, Tabellen-URL und Domain richtet ihr bei der Installation selbst ein.

Was das Tool kann

  • Erfassen in Sekunden: Bezeichnung, Standort, Foto direkt aus der Kamera, Status
  • Automatischer Status aus den drei Prüfpunkten Audio, Bild und Sprache
  • Übersicht mit Kacheln, Suche und Statusfilter
  • Fortlaufende IDs (MON-001, MON-002 …), die nie doppelt vergeben werden
  • Protokoll jeder Änderung mit Zeit und Person im Blatt Protokoll
  • Offline-Warteschlange: Änderungen ohne Netz werden nachgereicht
  • Als App installierbar über „Zum Home-Bildschirm“

So kommt ihr zum Laufen

  1. Google Tabelle anlegen und das Apps Script einfügen (Teil 1)
  2. Server mit install.sh aufsetzen (Teil 2)
  3. Am Handy die Seite öffnen und im Setup-Tab URL und Token eintragen (Teil 3)

Dafür braucht ihr ein Google-Konto, einen Linux-Server oder LXC-Container (Ubuntu 22.04/24.04) und eine Domain mit HTTPS. Ohne HTTPS gibt das Handy die Kamera nicht frei.

Anpassen

Was Wo
ID-Präfix (MON) und Stellenzahl apps-script/Code.gs → CONFIG.ID_PREFIX, CONFIG.ID_PAD
Namen der Tabellenblätter apps-script/Code.gs → CONFIG.SHEET_NAME, CONFIG.LOG_SHEET_NAME
Statusbezeichnungen apps-script/Code.gs → STATUS und gleichlautend in web/index.html
Zugangsdaten am Gerät vorbelegen web/index.html → DEFAULTS (nicht committen, wenn echte Werte drinstehen)
Bildgröße, Upload-Limit, Port server/.env (Vorlage: server/.env.example)

Statusregeln

Jeder Eintrag hat drei Prüfpunkte: Audio, Bild, Sprache – jeweils JA, NEIN oder n.A.

Eingabe Ergebnis
alle bewerteten Punkte JA Funktionsfähig
teilweise NEIN Teilweise funktionsfähig
alle bewerteten Punkte NEIN Fehlerhaft
alle drei n.A. Deaktiviert
nichts erfasst Nicht geprüft

Ein einzelnes n.A. schließt nur diesen Punkt aus der Bewertung aus und zählt nie als Fehler. Beispiel: n.A. / NEIN / NEIN → Fehlerhaft (die zwei bewerteten Punkte sind beide nein), n.A. / JA / NEIN → Teilweise funktionsfähig.

Die Regeln stehen identisch in Code.gs (berechneStatus) und in index.html – das Sheet bleibt die maßgebliche Quelle, das Frontend zeigt die Vorschau sofort an.


Teil 1 – Google Tabelle einrichten

  1. Neue Tabelle auf sheets.new anlegen, z. B. „Monitore Veranstaltung 2026".
  2. Erweiterungen → Apps Script. Den Standardinhalt von Code.gs löschen und den Inhalt aus apps-script/Code.gs einfügen.
  3. Ganz oben CONFIG.API_TOKEN durch ein langes Zufallstoken ersetzen. Erzeugen z. B. mit:
    openssl rand -hex 24
    
    Dieses Token brauchst du gleich noch zweimal (Server und Oberfläche).
  4. Speichern. Im Editor die Funktion testStatusLogik auswählen und Ausführen – beim ersten Mal Zugriff freigeben. Im Ausführungsprotokoll muss „Alle 9 Testfälle bestanden" stehen.
  5. Zurück in der Tabelle: Seite neu laden, dann Menü Monitor-Check → Tabelle einrichten. Damit entstehen die Blätter Monitore und Protokoll samt Spaltenbreiten und Dropdowns.
  6. Im Apps-Script-Editor: Bereitstellen → Neue Bereitstellung → Typ: Web-App
    • Beschreibung: Monitor-Check API
    • Ausführen als: Ich
    • Zugriff: Jeder ← zwingend, sonst antwortet die API mit einer HTML-Anmeldeseite
    • Bereitstellen, Berechtigungen bestätigen, die …/exec-URL kopieren.

Nach jeder Änderung an Code.gs: Bereitstellen → Bereitstellungen verwalten → Bearbeiten → Version: Neu → Bereitstellen. Die URL bleibt dabei gleich.


Teil 2 – Server aufsetzen

Der schnelle Weg: Projektordner auf den Server kopieren und install.sh laufen lassen – das erledigt alles ab Abschnitt 2.2.

# auf deinem Rechner (IP anpassen)
scp -r . root@192.168.1.50:/root/monitor-check-quelle

# auf dem Server
cd /root/monitor-check-quelle
sudo bash install.sh

Das Skript fragt nach Domain und E-Mail, erzeugt ein API-Token, installiert Node 20, nginx, den Dienst und holt das Let's-Encrypt-Zertifikat. Am Ende stehen alle Zugangsdaten auf dem Bildschirm und in /opt/monitor-check/ZUGANGSDATEN.txt.

Ohne Rückfragen:

sudo bash install.sh --domain monitore.deine-domain.de --email du@deine-domain.de --yes

Nützliche Schalter: --dry-run zeigt nur, was passieren würde. --update spielt nach Änderungen an web/ oder server/ die neuen Dateien ein und startet den Dienst neu. --no-tls und --no-firewall überspringen Zertifikat bzw. ufw. --help listet alles auf.

Hinter einem vorgeschalteten Reverse-Proxy

Wenn TLS bereits auf einem vorgelagerten nginx liegt, übernimmt der Container nur HTTP:

sudo bash install.sh --behind-proxy --public-url https://monitore.deine-domain.de --yes

Das überspringt certbot, lässt den Container auf Port 80 lauschen und setzt PUBLIC_URL trotzdem auf https – wichtig, denn diese Adresse landet als Bild-Link in der Tabelle. Bei http:// blockiert der Browser die Bilder später als Mixed Content.

Am Ende schreibt das Skript eine passende Vorlage nach /opt/monitor-check/PROXY-SNIPPET.conf, die du auf dem vorgelagerten Proxy einsetzen kannst. Ein Punkt daraus entscheidet über Erfolg oder Frust:

client_max_body_size 20m;

Fehlt die Zeile im äußeren Proxy, brechen Foto-Uploads mit 413 Request Entity Too Large ab – der Container selbst ist dann gar nicht schuld.

Der lokale nginx im Container darf auch ganz entfallen; dann hört Node direkt auf 0.0.0.0:8080 und der Proxy zielt dorthin:

sudo bash install.sh --behind-proxy --no-nginx --public-url https://monitore.deine-domain.de --yes

Der Unterschied ist klein: Mit lokalem nginx werden die Fotos direkt von der Platte ausgeliefert statt durch Node. Bei ein paar hundert Bildern spielt das keine Rolle – wähle, was besser in deine Landschaft passt.

Läuft das Skript durch, geht es direkt bei Teil 3 weiter. Die Abschnitte 2.2 bis 2.7 beschreiben dieselben Schritte von Hand – nützlich zum Nachvollziehen oder Reparieren.

2.1 Container erstellen (auf dem Proxmox-Host)

Getestet mit Ubuntu 22.04/24.04 in einem unprivilegierten LXC-Container (Proxmox). Alle Befehle als root im Container.

pct create 120 local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst \
  --hostname monitor-check \
  --cores 2 --memory 1024 --swap 512 \
  --rootfs local-lvm:8 \
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \
  --features nesting=1 \
  --unprivileged 1 \
  --onboot 1
pct start 120
pct enter 120

Ein bestehender Container tut es genauso – dann direkt bei 2.2 weiter.

2.2 Grundpakete

apt update && apt -y upgrade
apt -y install curl git nginx ca-certificates

# Node.js 20 LTS
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt -y install nodejs
node -v          # sollte v20.x zeigen

2.3 Benutzer und Verzeichnisse

adduser --system --group --home /opt/monitor-check monitor
mkdir -p /opt/monitor-check /var/lib/monitor-check/uploads

2.4 Dateien einspielen

Ordner server/ und web/ aus diesem Projekt nach /opt/monitor-check/ kopieren – z. B. vom Arbeitsrechner aus:

# auf deinem Rechner, IP anpassen
scp -r server web root@192.168.1.50:/opt/monitor-check/

Dann im Container:

cd /opt/monitor-check/server
npm install --omit=dev

sharp bringt fertige Binärpakete mit; sollte der Build doch starten, hilft apt -y install build-essential python3.

2.5 Konfiguration

cd /opt/monitor-check/server
cp .env.example .env
nano .env

Anzupassen:

PORT=8080
HOST=127.0.0.1
API_TOKEN=<dasselbe Token wie in Code.gs>
PUBLIC_URL=https://monitore.deine-domain.de
UPLOAD_DIR=/var/lib/monitor-check/uploads
WEB_DIR=/opt/monitor-check/web
ALLOWED_ORIGINS=https://monitore.deine-domain.de

PUBLIC_URL ist wichtig: genau diese Adresse landet als Bild-Link in der Tabelle.

chown -R monitor:monitor /opt/monitor-check /var/lib/monitor-check
chmod 600 /opt/monitor-check/server/.env

2.6 Als Dienst starten

cp /opt/monitor-check/server/monitor-check.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now monitor-check
systemctl status monitor-check --no-pager
curl -s localhost:8080/gesundheit     # {"ok":true,…}

Logs mitlesen: journalctl -u monitor-check -f

2.7 nginx und HTTPS

cp /opt/monitor-check/server/nginx-monitor-check.conf /etc/nginx/sites-available/monitor-check
sed -i 's/monitore.example.org/monitore.deine-domain.de/' /etc/nginx/sites-available/monitor-check
ln -sf ../sites-available/monitor-check /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx

# Zertifikat (DNS muss vorher auf den Server zeigen)
apt -y install certbot python3-certbot-nginx
certbot --nginx -d monitore.deine-domain.de

HTTPS ist Pflicht. Ohne TLS gibt die Handy-Kamera im Browser kein Bild frei und fetch zu Google wird von der Seite aus blockiert.

Optional Firewall:

apt -y install ufw
ufw allow 22,80,443/tcp && ufw --force enable

Teil 3 – Oberfläche verbinden

https://monitore.deine-domain.de am Handy öffnen. Beim ersten Start landest du im Tab Setup:

Feld Wert
Apps-Script Web-App URL die …/exec-URL aus Schritt 1.6
API-Token dasselbe Token wie in Code.gs und .env
Upload-Endpoint https://monitore.deine-domain.de/api/upload
Dein Name wird je Prüfung als „Prüfer" gespeichert

Speichern, dann Verbindung testen – die Meldung „Verbindung ok" bestätigt Schritt 1 und 2.

Die Werte liegen im localStorage des Browsers, also pro Gerät einmal eintragen. Willst du das vorbelegen, trage sie in web/index.html oben im Block DEFAULTS ein und lade die Datei neu auf den Server.

Auf dem iPhone: Teilen → Zum Home-Bildschirm. Danach startet das Tool wie eine App im Vollbild.


Bedienung

Erfassen – Bezeichnung eingeben, optional Standort, aufs Fotofeld tippen (öffnet direkt die Kamera). Der Status lässt sich sofort mitsetzen oder später nachtragen. Die ID vergibt das Skript automatisch: MON-001, MON-002, …

Übersicht – Kacheln zeigen die Verteilung, darunter Suche und Statusfilter. Ein Tippen auf einen Eintrag öffnet die Detailansicht mit den drei Schaltern. Erneutes Tippen auf einen bereits gewählten Wert hebt die Auswahl wieder auf.

Löschen – In der Detailansicht ganz unten „Eintrag löschen", nach Rückfrage verschwindet die Zeile aus der Tabelle. Alternativ die Zeile direkt im Sheet löschen. Vergebene IDs werden dabei nie erneut vergeben, auch nicht die des zuletzt angelegten Eintrags – der Zähler steht in den Skript-Eigenschaften. Das zugehörige Foto bleibt auf dem Server liegen; siehe „Wartung" zum Aufräumen.

Offline – Bei Verbindungsabbruch wandern Neuanlagen und Statusmeldungen in eine lokale Warteschlange (Anzeige oben rechts) und gehen automatisch raus, sobald das Netz zurück ist. Manuell auslösen im Setup-Tab. Fotos brauchen dagegen eine Verbindung – ohne Netz den Eintrag ohne Bild anlegen und das Foto später über die Tabelle nachtragen.


Tabellenstruktur

Blatt Monitore:

Spalte Inhalt
A ID MON-001 fortlaufend
B Bezeichnung Freitext
C Standort Freitext
D Bild-URL Link auf dein /uploads/…
E Audio / F Bild / G Sprache JA / NEIN / n.A.
H Status automatisch berechnet, Zeile wird eingefärbt
I Notiz Freitext
J Erfasst am, K Geprüft am, L Geprüft von Zeitstempel und Person

Blatt Protokoll schreibt jede Änderung mit – Zeitpunkt, ID, Aktion, Status, Person.

Direkt in der Tabelle bearbeitete Werte werden nicht automatisch neu bewertet. Dafür gibt es Monitor-Check → Alle Status neu berechnen.

Bilder als Vorschau in der Tabelle: eine leere Spalte ergänzen und dort =BILD(D2) eintragen.


Wartung

# Dienst neu starten (nach Änderungen an server.js oder .env)
systemctl restart monitor-check

# Oberfläche und Server aktualisieren – neue Dateien hochladen, dann
sudo bash install.sh --update
# Browser-Cache: Seite mit gedrücktem Reload neu laden

# Platzbedarf der Fotos
du -sh /var/lib/monitor-check/uploads

# Sicherung der Bilder
tar czf uploads-$(date +%F).tar.gz -C /var/lib/monitor-check uploads

Verwaiste Fotos gelöschter Einträge aufräumen: Spalte D des Sheets als CSV exportieren, auf den Server legen und abgleichen.

# behaelt nur Dateien, die noch in der Tabelle verlinkt sind
cd /var/lib/monitor-check/uploads
grep -o '[^/]*\.jpg' /root/bild-urls.csv | sort -u > /tmp/benutzt.txt
ls *.jpg | sort > /tmp/vorhanden.txt
comm -23 /tmp/vorhanden.txt /tmp/benutzt.txt        # erst anschauen
comm -23 /tmp/vorhanden.txt /tmp/benutzt.txt | xargs -r rm --   # dann loeschen

Bilder werden auf max. 1600 px verkleinert und als JPEG (Qualität 78) gespeichert – rund 150–400 kB pro Foto. 1000 Einträge belegen also etwa 300 MB. Anpassbar über MAX_IMAGE_PX und JPEG_QUALITY in der .env.

Fehlersuche

Symptom Ursache
„Unerwartete Antwort – Web-App-Zugriff auf ‚Jeder' gesetzt?" Bereitstellung steht auf „Nur ich". In den Bereitstellungen auf Jeder ändern.
„Nicht autorisiert" Token stimmt nicht überein. Muss in Code.gs, .env und im Setup-Tab identisch sein.
Änderungen an Code.gs wirken nicht Neue Version bereitstellen, nicht nur speichern.
Kamera öffnet nicht Seite läuft über http statt https.
Upload bricht bei großen Fotos ab client_max_body_size in jedem nginx davor und MAX_UPLOAD_MB in der .env erhöhen.
Bilder erscheinen nicht, Konsole meldet Mixed Content PUBLIC_URL steht auf http://, die Seite läuft über https://. In der .env korrigieren, Dienst neu starten. Bereits gespeicherte Links im Sheet per Suchen-und-Ersetzen anpassen.
Bild-Link im Sheet zeigt 127.0.0.1 PUBLIC_URL in der .env setzen und Dienst neu starten.
Nichts geht mehr journalctl -u monitor-check -n 50 --no-pager

Sicherheit

Das Token schützt die Schnittstelle gegen zufällige Zugriffe, ist aber kein Login – wer die URL und das Token hat, kann schreiben. Für eine interne Veranstaltung reicht das. Soll es enger sein, lege in nginx zusätzlich eine Basic-Auth über location / (nicht über /api/upload, sonst scheitert der Upload aus der Seite heraus) oder beschränke den Vhost auf das Veranstaltungs-Netz per allow/deny.


Dateien

Datei Zweck
install.sh richtet den Server komplett ein (Ubuntu 22.04/24.04)
apps-script/Code.gs Backend an der Google Tabelle, JSON-API, Statusberechnung
web/index.html die komplette Oberfläche in einer Datei
server/server.js Foto-Upload und Auslieferung der Oberfläche
server/.env.example Konfigurationsvorlage, wird zur .env (nicht im Repo)
server/monitor-check.service systemd-Unit
server/nginx-monitor-check.conf nginx-Vhost mit TLS-Vorbereitung

Powered by TurnKey Linux.