Files
projektuebersicht/README.md
T

12 KiB

Projektübersicht — README

Übersicht

Dieses Projekt ist eine lokale Weboberfläche zur Verwaltung von TGA-Projekten (Elektro, HLS, Architektur) über wöchentliche Sitzungen. Die Anwendung besteht aus:

  • einem Frontend mit Test.html als der einen Anwendungsseite — sie enthält alle Bereiche einschließlich des Projektbereichs eines einzelnen Projekts (Terminplan/GANTT, Aufgaben, Dateien, Einstellungen) — dazu styles.css, plan-styles.css und den JS-Modulen unter public/js/
  • einem einfachen Node.js-/Express-Server in server.js
  • einem Datenspeicher in einer SQLite-Datenbank (node:sqlite, benötigt Node ≥ 22.13) unter sessions/projektuebersicht.db
  • einem Docker-Setup (Docker/Dockerfile + docker-compose.yml im Projektstamm)

Datei- und Komponentenübersicht

Wichtige Laufzeit-Dateien

  • server.js

    • Node.js/Express-Server
    • dient als API für das Frontend
    • stellt statische Dateien (Test.html, die Module unter js/, styles.css, plan-styles.css, etc.) bereit; statische Assets werden mit Cache-Control: no-store ausgeliefert
    • implementiert Endpunkte:
      • GET / → liefert Test.html
      • GET /load-all?department=… → lädt alle Sitzungen plus globale Personenliste einer Abteilung
      • POST /save-week {department, week, baseUpdatedAt} → speichert/aktualisiert eine Sitzung; mit baseUpdatedAt (die vom Client gehaltene Revision = updatedAt aus load-all) erkennt der Server veraltete Speicherungen und antwortet dann mit HTTP 409 {ok:false, conflict:true, …}; auch gelöschte Sitzungen werden mit nicht-leerer Basis nicht wiederbelebt (409). Erfolgreiche Saves antworten {ok:true, updatedAt} (neue Revision)
      • POST /save-people {department, people} → ersetzt die globale Personenliste einer Abteilung
      • POST /delete-week {department, label} → löscht eine Sitzung
      • GET /health → Gesundheitscheck ({ok:true})
      • Deep Links je Abteilung + Tab, z. B. GET /HLS/Auslastung oder GET /ELT/Projektübersicht → liefert Test.html; gültige Tab-Slugs sind Projektübersicht | Auslastung | Projekte | Projektbeteiligte, alles andere ergibt 404
      • GET /Projektplan(/<ProjName>)? → liefert ebenfalls Test.html; der Projektbereich ist seit dem Umbau kein eigenes Dokument mehr, sondern ein Bereich dieser Seite, den applyUrlRoute() (public/js/ui.js) aus der Adresse auswählt. Die Identifikation erfolgt über die Query-Parameter weekLabel und projNr, der Projektname ist nur ein lesbares Pfad-Segment. Alte Links auf /project-plan.html werden per 301 auf dieses Schema umgeleitet
    • validiert Abteilungen gegen ELT | HLS | ARCH (unbekannte fallen stillschweigend auf ELT zurück)
    • legt das sessions-Verzeichnis beim Start an, falls es nicht existiert
    • JSON-Body-Limit von 2 MB
    • beendet sich mit aussagekräftiger Fehlermeldung, wenn der Port belegt ist
  • package.json

    • definiert den Node.js-Startbefehl npm start
    • enthält Produktionsabhängigkeiten express und cors
  • package-lock.json

    • wird für reproduzierbare Docker-Builds verwendet (npm ci)
  • public/js/ (Module)

    • Die Client-Logik ist in kleine klassische Script-Dateien aufgeteilt (alle Funktionen global auf window, kein Bundler):
      • gemeinsame Helfer: globals.js, utils.js, ui.js, date-picker.js, server.js, store.js, weeks.js, gantt.js, showmode.js, tabs-auth.js, pdf.js, init.js
      • tab-spezifisch in eigenen Ordnern: board/board.js (Projektboard), people/people.js (Projektbeteiligte), projects/projects.js (Projekte), load/load.js (Auslastung)
      • Planungs-Module unter js/plan/ (plan-state, plan-build-gantt, plan-gantt, plan-drag, plan-modals, plan-schedule)
    • rendert das Projektboard, die Projekt- und Personenverwaltung sowie die Auslastungsansicht
    • lädt Daten über den Server und speichert Änderungen als JSON-Objekte in die SQLite-Datenbank zurück
    • verwendet currentDepartment zur Trennung von Abteilungen (ELT, HLS, ARCH)
    • speichert:
      • alle Sitzungen und die globale Personenliste pro Abteilung in sessions/projektuebersicht.db
    • sortiert Sitzungen nach Kalenderwoche, nicht alphabetisch
    • sperrt historische Sitzungen automatisch (bis auf die chronologisch letzte)
    • Personen sind global pro Abteilung verwaltet; historische Sitzungen behalten ihre lokalen Personenkopien
    • speichert keine Daten in localStorage (dort liegt nur UI-Zustand wie Abteilung, Theme und Header-Collapse)
  • Test.html

    • die Haupt-Benutzeroberfläche der Anwendung (Tabs: Projektboard, Auslastung, Projekte, Projektbeteiligte)
    • lädt styles.css und die JS-Module aus js/ in fester Reihenfolge (siehe AGENTS.md)
    • enthält die Abteilungsauswahl, Sitzungsnavigation, Tab-Navigation, das Passwort-Modal sowie PDF-Export
    • lädt CryptoJS (Passwortprüfung) und pdfmake (PDF-Export) von cdnjs.cloudflare.com — diese Funktionen benötigen daher Internetzugang
  • Projektbereich (Bereich #plan in Test.html, Module unter js/plan/)

    • der eigene Bereich EINES Projekts mit Dashboard, Terminplan (GANTT/TODOs/Meilensteine), Aufgaben, Dateien und Einstellungen
    • wird über openProjectPlan() (js/gantt.js) geöffnet — ein gewöhnlicher Bereichswechsel über showTab('plan'), genau wie vom Dashboard ins Projektboard; Menüband und Seitenleiste bleiben stehen
    • war bis zum Umbau ein eigenes Dokument project-plan.html mit nachgebauter, abgespeckter Seitenleiste; die Datei ist entfallen, ihre Stile liegen jetzt in plan-styles.css
  • plan-styles.css

    • die Stile des Projektbereichs (früher ein <style>-Block in project-plan.html)
  • Bereich „Einstellungen" (js/settings/settings.js)

    • gehört dem angemeldeten Konto selbst: Stammdaten zur Ansicht und der Passwortwechsel (POST /change-password). Der Dialog erscheint auch erzwungen direkt nach der Anmeldung, solange das Konto must_change_password trägt
  • Bereich „Admin" (js/admin/admin.js, nur für Administratoren)

    • gegliedert in einzelne Abschnitte, zwischen denen die aufklappbare Gruppe „Admin" in der Seitenleiste umschaltet; sichtbar ist immer genau einer, der gewählte steht im URL-Fragment (z. B. /Admin#auslastung) und ist damit verlinkbar
    • Abschnitte: „Benutzerverwaltung" (Konten, Rollen, Wochenstunden, Abwesenheiten — bis zum Umbau die eigene Seite admin-users.html, alte Links werden per 301 umgeleitet), „Honorar" (Stundensatz, Anteile je Leistungsphase), „Auslastung" (Wochenstunden einer vollen Stelle, Ampel-Schwellen, Balkenskala, Aufwand je Leistungsphase und Rolle), „Termine & Sitzungen" (Arbeitsstunden je Werktag, automatische Sperre), „Feiertage" (die gesetzlichen Feiertage eines Jahres werden berechnet — feste Termine plus alles, was am Osterdatum hängt — und auf Knopfdruck übernommen; kein Netzdienst, kein Internetzugang nötig), „Aufgaben-Vorlagen", „Betrieb & Sicherheit" (aufbewahrte Backups, Gültigkeit einer Anmeldung, Anmeldebremse) und „Datenbank & Sitzungen" (DB Backup, DB Import, Sitzung löschen)
    • all diese Werte waren vorher Konstanten im Quelltext; gelesen werden sie über GET /app-settings (jedes Konto — das Frontend rechnet damit), geschrieben über PUT /app-settings (nur Administratoren, serverseitig über requireRole('admin') abgesichert)
    • die vertraglichen Wochenstunden je Person stehen am Benutzerkonto (Benutzerverwaltung) und sind die Bezugsgröße der Auslastungs-Ampel: Eine halbe Stelle gilt schon bei halber Last als voll ausgelastet
  • styles.css

    • Layout und Styling der Oberfläche

Docker-bezogene Dateien

  • Docker/Dockerfile

    • Basis-Image: node:22-alpine (nötig, da node:sqlite erst ab Node 22.13 ohne Flag stabil verfügbar ist)
    • kopiert package.json und package-lock.json, installiert Produktionsabhängigkeiten mit npm ci
    • kopiert server.js und public/ nach /app
    • legt sicherheitshalber /app/sessions an
    • läuft als nicht-root-User node
    • enthält einen HEALTHCHECK auf /health
    • startet node server.js
  • docker-compose.yml (im Projektstamm)

    • definiert den Service projektuebersicht
    • baut das Image mit Build-Kontext . und Docker/Dockerfile
    • mappt Port 3003:3003
    • bindet das Host-Verzeichnis ./sessions in den Container nach /app/sessions
    • setzt restart: unless-stopped
    • definiert einen healthcheck
  • .dockerignore

    • schließt unnötige Dateien aus dem Docker-Build aus: node_modules/, npm-debug.log, .git, .gitignore, Docker/* (außer Docker/Dockerfile)

Sonstige Dateien

  • dein_bild.ico

    • optionales Icon, wird vom Server statisch ausgeliefert, wenn angefragt
  • AGENTS.md

    • Projektnotizen / Dokumentation, aber nicht Teil des Anwendungslaufs

Persistenz und Datenfluss

Speicherung

  • Alle persistierten Daten werden in einer SQLite-Datenbank (node:sqlite, DatabaseSync, WAL-Modus, PRAGMA foreign_keys = ON) unter sessions/projektuebersicht.db gespeichert.
  • Das Schema ist vollständig relational (19 Tabellen): weeks, week_people (+ week_people_roles), attendance, projects, project_lph, project_assign, project_aufwand, project_aktuelle_lp, project_plan, plan_people, plan_todos (+ plan_todo_assignees, plan_todo_deps), plan_milestones (+ plan_milestone_deps), people (+ person_roles, person_absences). Projekt-/Personen-IDs bleiben dadurch über Neustarts stabil.
  • Der Datenbankpfad ist über die Umgebungsvariable DB_PATH übersteuerbar (für Tests/Backups), Standard ist sessions/projektuebersicht.db.

Server-API

  • Der Server wird in server.js erstellt und startet auf Port 3003 oder dem Wert von process.env.PORT.
  • Das Frontend ruft den Server über window.location.origin an (Fallback http://localhost:3003 bei file://-Öffnung).

Wo werden die Daten gespeichert?

  • Das Frontend schreibt über den Server in die SQLite-Datenbank.
  • In js/store.js speichert die Anwendung nur geänderte Sitzungen (Dirty-Tracking über markWeekDirty()/markPeopleDirty()) via /save-week (Sitzungen) bzw. /save-people (globale Personen); ein In-Flight-Guard verhindert Doppel-Speicherungen. Jede Sitzung führt einen Revisions-Zeitstempel (updated_at, übertragen als updatedAt); speichert ein Client mit veralteter Revision (baseUpdatedAt), antwortet der Server mit HTTP 409 und der Client lädt nur diese eine Sitzung neu (andere ungespeicherte Änderungen bleiben erhalten).
  • Der Server zerlegt die JSON-Objekte in die relationalen Tabellen (serializeWeek()/loadWeeks()) in einer Transaktion pro Sitzung. Beim Start migriert migrateLegacySchema() idempotent ein altes Single-JSON-Dokument-Schema in das relationale Schema; anschließend ergänzt migrateWeeksUpdatedAt() die updated_at-Spalte der weeks-Tabelle (idempotent). PRAGMA busy_timeout = 5000 verhindert Fehler bei parallelen Schreibzugriffen.

Betrieb

Lokal mit Node.js (Node ≥ 22.13)

npm install
npm start

Danach ist die Anwendung erreichbar unter http://localhost:3003.

Falls der Port belegt ist:

PORT=3004 npm start

Mit Docker

Im Projektstamm ausführen:

docker compose up --build

Danach ist die Anwendung erreichbar unter:

http://localhost:3003

Wichtige Hinweise

  • Der Server benötigt Lese-/Schreibzugriff auf sessions/ (für die SQLite-Datenbank und das Docker-Bind-Mount).
  • Die Docker-Compose-Konfiguration liegt im Projektstamm und mountet ./sessions in den Container. Achte darauf, dass der relative Pfad im Kontext korrekt ist, wenn du docker compose aus einem anderen Verzeichnis startest.
  • js/store.js und js/server.js arbeiten mit Abteilungsparametern und speichern Daten abteilungsweise getrennt.
  • Die Passwortfunktion (Tabs „Projekte“/„Projektbeteiligte“, Sitzungslöschung, Entsperren) ist nur ein einfacher Client-Mechanismus im Frontend (SHA256-Vergleich) und kein echter Sicherheitsmechanismus.
  • Globale Personen werden pro Abteilung in der Datenbank verwaltet. Wird eine Person global gelöscht, bleibt sie in bereits existierenden Sitzungen sichtbar (Wochen-Personenkopien).
  • CryptoJS und pdfmake werden von cdnjs.cloudflare.com geladen — PDF-Export und Passwortprüfung funktionieren ohne Internet nicht.