Zum Inhalt springen

Architektur

SchichtTool
RuntimeNode.js 22
HTTPExpress 5
BrowserPlaywright 1.59 (Chromium)
DBSQLite — nativ via node:sqlite
Pushweb-push
V2-FrontendSvelteKit 2 + Svelte 5 (adapter-static)
V1-FrontendVanilla-JS-PWA unter /mobile/
Testsnode:test
tocco-mate/
├── src/
│ ├── server.js Express-Composition + Boot
│ ├── auth.js Bearer-Token + Anti-Brute-Force
│ ├── ratelimits.js express-rate-limit-Instanzen
│ ├── scheduler.js Intervall- / Wochenplan-Logik
│ ├── runScrape.js Scrape-Cycle-Orchestrierung
│ ├── sse.js Server-Sent-Events Broadcast
│ ├── pushValidate.js SSRF-Allowlist für Push-Endpoints
│ ├── secretCrypto.js AES-256-GCM für settings.json-Secrets
│ ├── state.js Geteilter Mutable-State
│ ├── cli.js CLI-Entry
│ ├── settings.js Settings-Persistenz (mit Encryption)
│ ├── scraper.js Playwright Login + Scraping
│ ├── push.js Web-Push (VAPID, FCM/Mozilla/Apple)
│ ├── logger.js Logging
│ ├── routes/ 11 Express-Route-Module
│ ├── db/ SQLite-Layer (9 Module)
│ ├── bot/ Telegram-Bot (8 Module)
│ └── shared/ envLoader, escapeHtml, apiError
├── test/unit/ Unit-Tests
├── web-svelte/ V2-Frontend
├── dist/ Build-Output (gitignored)
├── web/
│ ├── mobile/ Legacy PWA
│ ├── floorplans/ Geteilte RaumView-Helper
│ └── assets/ Logo, Icons
├── data/ Runtime (Docker-Volume)
├── Dockerfile
└── docker-compose.yml
ModulAufgabe
index.jsRouter-Aggregation
status.jsGET /api/status
settings.jsGET/PATCH /api/settings
noten.jsGET /api/noten, /:id/pruefungen, /api/history/:id
stundenplan.jsGET /api/stundenplan, POST .../clear
stats.jsGET /api/stats
scrape.jsPOST /api/scrape
push.jsVAPID, subscribe, test
logs.jsGET /api/logs
events.jsSSE GET /api/events
static.jsAsset-Serving (/, /mobile/, Floorplans)
ModulAufgabe
index.jsConnection-Singleton, Migrations, Bootstrap
schema.jsCREATE TABLE-Statements
queries.jsGenerische Helper
parsers.jsDOM → Domain-Objekt
noten.jsNoten-CRUD + History-Append
stundenplan.jsTermin-CRUD + Raumwechsel-Detection
pruefungen.jsLB/ZP/OTHER-CRUD + History
stats.jsAggregat-Queries
push.jsSubscriptions
ModulAufgabe
index.jsLong-Polling, Routing
state.jsPer-User-State
telegram.jsTelegram-API-Wrapper
format.jsNoten- / Termin-Formatter
keyboards.jsInline-Keyboards
screens.jsAntwort-Templates
handlers.jsCommand-Handler
notify.jsPush-Bridge (Web-Push → Telegram)
TabelleInhalt
notenModul-Stammdaten + aktuelle Note + Frisch-Marker
noten_historyAppend-only Verlauf jeder Modulnoten-Änderung
noten_pruefungenLB / ZP / OTHER pro Modul mit Gewicht
pruefungen_historyAppend-only Verlauf jeder ZP/LB-Bewertungs-Änderung
stundenplanTermine mit Datum, Zeit, Raum, Dozent + Raumwechsel-Marker
push_subscriptionsPWA-Push-Subscriptions (endpoint + Krypto-Keys)

DB-Connection ist seit v1.0.0 ein Boot-Singleton — Migrationen + reclassifyOtherPruefungen laufen einmal beim Start, alle Routen / Bot-Screens nutzen den geteilten Handle.

1. envLoader → .env + ENV merge
2. settings.load() → data/settings.json (mit Decryption)
3. db.init() → Connection + Migrations + Reclassify
4. push.init() → VAPID-Keys laden / generieren
5. server start → Express + Static
6. scheduler.start() → Intervall/Wochenplan
7. bot.start() (opt) → Telegram-Long-Polling
  • Vanilla-PWA (/mobile/) ist langlebig — kein Build, läuft unverändert über Jahre, schlanker Service-Worker
  • SvelteKit-SPA (/) für die Desktop-Erfahrung mit komplexeren Interaktionen (Filter, Tabellen, Charts)

Beide werden vom selben Express-Server gehostet — dist/ für SvelteKit, web/mobile/ für Vanilla.

  • Native Node-API seit v22.5
  • Keine native Build-Dependency mehr → schlankerer Container
  • Performance ausreichend für unsere Größenordnung
  • Vor v1.0.0 öffnete jede Route eine neue Connection → Migrations liefen mehrfach
  • Singleton + reclassifyOtherPruefungen einmal beim Start → robust, performant

Pragmatik: das At-Rest-Encryption schützt gegen versehentliche Leaks (Backup, Snapshot, Sharing). Gegen Shell-Access auf den laufenden Host hilft es nicht — dafür gibt’s Backup-Encryption.