Wandtafel-Dashboard, Dateibereinigung und Auslastungs-Vereinfachung
Neue Wandtafel (Touch-Dashboard für Kiosk-Anzeige): Auslastung/Besprochen je Gewerk, Aufgaben-Kennzahlen, Ereignis-Feed nach Art gruppiert, vollständige Projektliste zum Scrollen, automatischer Rücksprung nach Untätigkeit mit sichtbarem Countdown. Eigene Kiosk-Rolle ohne Fachrolle und ohne Schreibrechte. Auslastung: Möglichkeit zum Wechsel der ausgewerteten Sitzung entfernt. Aufräumen nicht mehr benötigter Dateien, README auf aktuellen Stand gebracht. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bc30f2900b
commit
db63a29365
47 files changed
+16486
-3768
No files matched your search
@@ -1,145 +1,129 @@
|
||||
# Projektübersicht — README
|
||||
# Projektübersicht
|
||||
|
||||
## Übersicht
|
||||
Dieses Projekt ist eine lokale Weboberfläche zur Verwaltung von TGA-Projekten (Elektro, HLS, Architektur) über wöchentliche Sitzungen. Die Anwendung besteht aus:
|
||||
Werkzeug für ein Ingenieurbüro der technischen Gebäudeausrüstung (TGA), um
|
||||
Projekte über wöchentliche Sitzungen hinweg zu verfolgen: Leistungsphasen nach
|
||||
HOAI, Termine, Personaleinsatz, die wöchentliche Teambesprechung und die
|
||||
Dokumentenfreigabe. Single-Page-App ohne Build-Schritt: Vanilla JS/HTML/CSS
|
||||
im Frontend, Node.js/Express im Backend, Daten in SQLite.
|
||||
|
||||
- einem Frontend aus zwei HTML-Einstiegen (`Test.html` für die Hauptansicht mit Tabs, `project-plan.html` für die Projektplanung/GANTT-Ansicht) plus `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)
|
||||
## Technologie
|
||||
|
||||
## Datei- und Komponentenübersicht
|
||||
- **Frontend**: klassische, unmodulare `<script>`-Dateien unter `public/js/`
|
||||
— alle Funktionen liegen global auf `window`, kein Bundler, kein Framework.
|
||||
**Eine** HTML-Datei, `public/App.html`, bildet die gesamte Oberfläche ab
|
||||
(Seitenleiste + alle Bereiche inklusive des Projektbereichs eines einzelnen
|
||||
Projekts).
|
||||
- **Backend**: Node.js (≥ 22.13, wegen `node:sqlite`) + Express, alles in
|
||||
einer einzigen `server.js`.
|
||||
- **Datenbank**: SQLite über das eingebaute `node:sqlite`-Modul (WAL-Modus,
|
||||
vollständig relational, keine Einzeldatei je Woche), Datei unter
|
||||
`sessions/projektuebersicht.db`.
|
||||
- Kein Linter, kein Formatter, keine Testsuite. Verifikation läuft manuell:
|
||||
Server starten, Bereich im Browser ausprobieren, SQLite-Datei prüfen.
|
||||
|
||||
### Wichtige Laufzeit-Dateien
|
||||
- `server.js`
|
||||
- Node.js/Express-Server
|
||||
- dient als API für das Frontend
|
||||
- stellt statische Dateien (`Test.html`, `project-plan.html`, die Module unter `js/`, `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 /<Dept>/Projektplan(/<ProjName>)?` → liefert `project-plan.html` (GANTT-Ansicht); die Identifikation erfolgt über die Query-Parameter `weekLabel` und `projNr`, der Projektname ist nur ein lesbares Pfad-Segment
|
||||
- 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
|
||||
## Starten
|
||||
|
||||
- `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
|
||||
|
||||
- `project-plan.html`
|
||||
- die Planungsansicht (GANTT/TODOs/Meilensteine) pro Projekt
|
||||
- öffnet sich in einem neuen Tab über `openProjectPlan()` (`js/gantt.js`)
|
||||
- lädt nur die gemeinsamen Helfermodule plus `js/plan/*` und window-übergreifend abgestimmte Pfade
|
||||
|
||||
- `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)
|
||||
### Lokal (Node.js ≥ 22.13)
|
||||
```bash
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
Danach ist die Anwendung erreichbar unter `http://localhost:3003`.
|
||||
|
||||
Falls der Port belegt ist:
|
||||
Erreichbar unter `http://localhost:3003`. Anderer Port:
|
||||
```bash
|
||||
PORT=3004 npm start
|
||||
```
|
||||
|
||||
### Mit Docker
|
||||
Im Projektstamm ausführen:
|
||||
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
`docker-compose.yml` liegt im Projektstamm, baut aus `Docker/Dockerfile`
|
||||
(`node:22-alpine`), mappt Port `3003` und bindet `./sessions` in den
|
||||
Container nach `/app/sessions` — die Datenbank und alle Uploads bleiben damit
|
||||
auf dem Host erhalten. `TZ=Europe/Berlin` ist gesetzt, weil mehrere
|
||||
Datumsvergleiche im Server von der lokalen Zeitzone abhängen.
|
||||
|
||||
Danach ist die Anwendung erreichbar unter:
|
||||
### Erste Anmeldung
|
||||
Die gesamte Anwendung verlangt eine Anmeldung. Ist die `users`-Tabelle beim
|
||||
ersten Start leer, legt der Server automatisch ein Admin-Konto
|
||||
(`admin`) mit einem zufälligen Passwort an, gibt es einmalig auf der Konsole
|
||||
aus und schreibt es zusätzlich nach `sessions/INITIAL_ADMIN_PASSWORD.txt`
|
||||
(liegt außerhalb von `public/`, wird also nie ausgeliefert). Das Konto muss
|
||||
sein Passwort beim ersten Login ändern.
|
||||
|
||||
```
|
||||
http://localhost:3003
|
||||
```
|
||||
## Bereiche der Anwendung
|
||||
|
||||
## 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.
|
||||
Seitenleiste, in dieser Reihenfolge:
|
||||
|
||||
- **Meine Aufgaben** — Dashboard und Startansicht nach dem Login: offene
|
||||
persönliche Aufgaben, Termine der eigenen Projekte, ausstehende
|
||||
Datei-Freigaben, Abwesenheiten von Kollegen.
|
||||
- **Projekte** — die eine Projektliste (Board), gruppiert, per Drag-and-Drop
|
||||
sortierbar.
|
||||
- **Wochenbericht** — die Tagesordnung der wöchentlichen Teambesprechung, je
|
||||
Gewerk (ELT/HLS/ARCH) gefiltert: jedes Projekt dieses Gewerks wird
|
||||
angesehen, mit Vergleich zur Vorwoche, Anwesenheitserfassung und PDF-Export.
|
||||
- **Auslastung** — Personalauslastung in tatsächlichen Wochenstunden,
|
||||
aufgeteilt nach Projekten (Lastband).
|
||||
- **Projektbeteiligte** — schreibgeschützte Übersicht der aktiven
|
||||
Benutzerkonten; Teammitglieder pflegt ausschließlich ein Administrator
|
||||
(Admin → Benutzerverwaltung).
|
||||
- **Planung** — ein von einem konkreten Projekt unabhängiger
|
||||
Terminplan-Sandkasten, z. B. um einen Zeitplan vorab durchzurechnen.
|
||||
- **Einstellungen** — das eigene Konto: Stammdaten, E-Mail, Passwort, eigene
|
||||
KI-Zugangsdaten für die Protokoll-Erkennung (siehe unten).
|
||||
- **Admin** *(nur Administratoren)* — Benutzerverwaltung, Honorar-Vorgaben,
|
||||
Auslastungs-Schwellen, Sitzungsverwaltung, Feiertage, Aufgaben-Vorlagen,
|
||||
Betrieb & Sicherheit, Datenbank-Backup/-Import.
|
||||
|
||||
### Projektbereich
|
||||
|
||||
Aus der Projektliste heraus öffnet sich zu einem Projekt ein eigener Bereich
|
||||
mit sieben Abschnitten: Dashboard, Terminplan (GANTT mit Aufgaben und
|
||||
Meilensteinen), Aufgaben, Leistung (erbrachter Leistungswert je Phase),
|
||||
Dateien, Protokolle (Besprechungsprotokolle) und Einstellungen
|
||||
(Projektstammdaten, Honorar, beauftragte Leistungsphasen).
|
||||
|
||||
## Datenhaltung
|
||||
|
||||
- Vollständig relationales SQLite-Schema statt eines JSON-Dokuments je Woche;
|
||||
Projekt- und Personen-IDs bleiben über Neustarts stabil.
|
||||
- Eine Sitzung ("KW XX / YYYY") entspricht einer Kalenderwoche. Der Wechsel
|
||||
in eine neue Sitzung läuft automatisch im Hintergrund (stündliche Prüfung)
|
||||
— es gibt keine "Neue Sitzung"-Schaltfläche mehr.
|
||||
- Der Server legt bei jedem Start automatisch einen Zeitstempel-Snapshot
|
||||
unter `sessions/backups/` an und behält nur die neuesten (Anzahl einstellbar
|
||||
unter Admin → Betrieb & Sicherheit). Ein Admin kann zusätzlich jederzeit
|
||||
ein Backup herunterladen oder eine Sicherung zurückspielen.
|
||||
- Hochgeladene Dateien (Freigabe-Workflow, importierte Protokolle) liegen
|
||||
unter `sessions/uploads/<uuid>.<endung>`, referenziert über die Datenbank.
|
||||
|
||||
## Authentifizierung & Rollen
|
||||
|
||||
Echte serverseitige Sitzungen (Cookie, `scrypt`-gehashte Passwörter) — kein
|
||||
clientseitiger Passwortschutz. Zwei Rollen: `admin` und `member`; nur
|
||||
wirklich destruktive bzw. administrative Aktionen (Benutzerverwaltung,
|
||||
Sitzung löschen/entsperren, DB-Import/-Backup) sind serverseitig auf Admins
|
||||
beschränkt. Zu viele Fehlversuche sperren ein Konto vorübergehend.
|
||||
|
||||
## Besonderheiten
|
||||
|
||||
- **Keine Abteilungstrennung mehr**: Alle Sitzungen, Projekte und Personen
|
||||
liegen in einer gemeinsamen Liste. `ELT`/`HLS`/`ARCH` bezeichnen heute nur
|
||||
noch die Fachrichtung eines Benutzerkontos bzw. die Gewerke eines Projekts.
|
||||
- **Protokoll-Import** kann ein hochgeladenes PDF/Word-Dokument
|
||||
KI-gestützt (eigener OpenAI- oder Claude-Schlüssel je Konto, auch ein
|
||||
lokal laufendes Modell möglich) in Besprechungspunkte umwandeln und fällt
|
||||
ohne Schlüssel oder bei einem Fehler automatisch auf eine
|
||||
Text-Heuristik zurück.
|
||||
- Der PDF-Export lädt `pdfmake` von `cdnjs.cloudflare.com` — benötigt
|
||||
Internetzugang.
|
||||
- Feiertage werden serverseitig berechnet (keine externe Abhängigkeit), die
|
||||
KI-gestützte Protokoll-Erkennung braucht dagegen Internetzugang bzw. ein
|
||||
erreichbares lokales Modell.
|
||||
|
||||
## Weiterführende Dokumentation
|
||||
|
||||
`CLAUDE.md` im Projektstamm enthält die ausführliche technische
|
||||
Dokumentation: Server-API, vollständiges Datenmodell, Architekturentscheidungen
|
||||
und ihre Begründung. Ausgangspunkt für tiefere Änderungen am Code.
|
||||
Reference in new issue
Block a user