# QR-Tabellen (table.lehrstun.de) ## Status **Phase:** MVP live auf https://table.lehrstun.de (Admin: /admin/, Basic Auth) **Stand:** 2026-07-05 ## Zweck Kleines selbst gehostetes Tool für den Schuleinsatz: CSV-Tabellen (Stationenlernen, Materiallisten, Linksammlungen) werden hochgeladen und als hübsche statische HTML-Seite veröffentlicht; Link-Spalten bekommen automatisch lokal erzeugte QR-Codes (kein externer API-Call, DSGVO). Dateneingabe bleibt bewusst in Excel/LibreOffice — Austausch ausschließlich über CSV. ## Quickstart ```bash cd D:\Claude-Projekte\qr-tabellen venv\Scripts\python -m flask --app app.main run # Admin: http://localhost:5000/admin/ venv\Scripts\python tests\test_engine.py # Engine-Selbsttest ``` ## Architektur - **Python 3.13 + Flask + segno** — einzige Abhängigkeiten (Jinja2 kommt mit Flask) - **Kein JS-Framework, keine DB** — Ablage im Dateisystem ``` app/ engine.py — Kern: CSV parsen/validieren, QR-SVGs (segno), HTML rendern (framework-frei) storage.py — Dateiablage: Schemas, CSV-Versionen, Veröffentlichung main.py — Flask-Admin: Schema-Designer, Dropzone, Linkliste, Versionen templates/ — table.html (öffentliche Seite) + admin/* static/ — table.css (Design-Tokens, wird in Seiten eingebettet) + admin.css data/tables//schema.json + versions/.csv (gitignored) public//index.html (gitignored) tests/test_engine.py — Selbsttest ohne pytest ``` ### Datenfluss 1. Schema online anlegen (Spalten: text, text_long, number, date, url, rating_5) 2. CSV-Vorlage herunterladen (Semikolon + UTF-8-BOM → Excel-tauglich) 3. Befüllte CSV in die Dropzone → Zuordnung per Dateiname, sonst Header-Signatur 4. Validierung (URLs, Bewertung 1-5, Zahlen); bei Fehlern wird nichts gespeichert 5. Version abgelegt + in sich geschlossene HTML-Seite nach `public//` gerendert ### Produktion (live seit 2026-07-05) - Server: Hetzner, `~/qr-tabellen` (Klon von Gitea `admin/qr-tabellen`, öffentliches Repo) - Öffentliche Seiten: Nginx statisch aus `/var/www/table` (verifiziert: bleiben bei App-Stopp online) - Admin: gunicorn (Port 8010) via systemd `qr-tabellen.service`, Nginx Basic Auth unter `/admin` - Zugangsdaten: lokal in `~/.config/claude-secrets/qr-tabellen.env`; Hash in `/etc/nginx/htpasswd-table` - TLS: certbot (Let's Encrypt), DNS via hetznerdns.py angelegt - Deploy-Update: `ssh herb@46.225.114.15`, `cd ~/qr-tabellen && git pull && sudo systemctl restart qr-tabellen` - `/var/www/table/material/` = reservierter Ordner für manuell hochgeladene statische Dateien (Arbeitsblätter, Glossare) — kein Tabellen-Slug darf "material" heißen ## Design Tokens in `table.css` (`:root`-Variablen: Farben, Fonts, QR-Größe, Breite). Systemfont-Stack mit Source Serif 4 / Fira Sans als Wunschfonts — bei Bedarf lokal hosten (kein Google-CDN, Schulkontext). Print-Media-Query vorhanden. ## Entscheidungen | Datum | Entscheidung | Begründung | |-------|-------------|------------| | 2026-07-05 | Python/Flask + segno statt Node | Passt zum Hetzner-Deploy-Muster; csv ist Stdlib, segno erzeugt SVG-QR ohne weitere Deps | | 2026-07-05 | Nur CSV im MVP, kein XLSX | Excel/LO speichern CSV; spart exceljs/openpyxl komplett | | 2026-07-05 | Öffentliche Seiten statisch, App nur fürs Admin | Schüler-Traffic trifft nie den Python-Prozess; robust bei App-Ausfall | | 2026-07-05 | QR-Codes als Inline-SVG in der Seite | Eine Datei pro Tabelle, keine Bild-Assets, skaliert per CSS | | 2026-07-05 | Versions-Erkennung: Dateiname → Header-Signatur → manuell | Kein Ratespiel; Vorlage heißt schon `.csv` | | 2026-07-05 | Kein Login in der App; Basic Auth via Nginx | Single-Admin, unveröffentlichte Slugs reichen für Schüler | | 2026-07-05 | CSV-Vorlage mit Semikolon + UTF-8-BOM | Deutsches Excel öffnet sie direkt korrekt | | 2026-07-05 | Fehlerhafte CSVs werden komplett abgelehnt | Klare Fehlermeldung statt halb veröffentlichter Tabelle | ## Blocker - Keine ## Nächste Schritte - [x] Deployment: DNS `table.lehrstun.de`, Gitea-Repo, gunicorn + systemd, Nginx (statisch + /admin Basic Auth), TLS - [ ] Demo-Tabelle (`demo-stationenlernen`) nach dem Ausprobieren im Admin löschen - [ ] Design-Feintuning (Tokens in table.css), ggf. Fonts lokal hosten - [ ] Später: XLSX-Direkt-Upload, QR-Label-Styling, XLSX-Re-Export mit QR-Bildern