# AGENTS.md ## Overview Single-page app for tracking engineering projects across weekly sessions ("Sitzungen"). Vanilla JS/HTML/CSS frontend + Node.js/Express server. No build step, no bundler, no tests. Data is persisted as semicolon-separated CSVs under `sessions/`. Two HTML entrypoints, both served statically by Express: - `Test.html` — the main app (tabs: Projektboard, Auslastung, Projekte, Projektbeteiligte). Served at `/`. - `project-plan.html` — per-project Gantt/TODO planning view, opened in a new tab via `openProjectPlan()` in `js/gantt.js`. Loads the shared helper modules (`globals`, `utils`, `ui`, `date-picker`, `csv`, `server`, `gantt`) plus the plan modules under `js/plan/` — NOT the full main module set. All UI strings/comments/CSV content are German. Preserve German in user-facing text. ## File structure ``` . ├── server.js # Express server + CSV API ├── package.json # deps: express, cors only ├── docker-compose.yml # at repo ROOT; build context ., dockerfile Docker/Dockerfile ├── Docker/Dockerfile # node:20-alpine ├── .dockerignore ├── .vscode/extensions.json ├── public/ │ ├── Test.html # main app (served at /) │ ├── js/ # main app modules (classic scripts, global fns) │ │ ├── globals.js # Konstanten (LPHS, ROLES, LPH-Farben, DEPARTMENTS) + db/currentDepartment │ │ ├── utils.js # esc, uid, Datum-/Differenz-Helfer, personIdForName, weekSortKey-Quelle │ │ ├── ui.js # LocalStorage-UI-State, Header-Collapse, Theme │ │ ├── date-picker.js # Datums-/Bereichspicker-Overlays │ │ ├── csv.js # CSV-Parser/Serializer + weekSortKey, filenameForWeek │ │ ├── server.js # baseUrl, sendCsvToServer, deleteCsvFromServer, blobToDataUrl │ │ ├── store.js # save/syncAllToServer, switchDepartment, load, seed │ │ ├── weeks.js # Wochen-Auswahl, -Erzeugung, -Klonen, Auto-Lock, -Löschung │ │ ├── board.js # Projektboard-Rendering, Status-Editor, Anwesenheit, Zuordnung │ │ ├── people.js # Personen-Tab-Rendering + Drag-and-Drop + Abwesenheiten │ │ ├── projects.js # Projekte-Tab-Rendering + Drag-and-Drop │ │ ├── load.js # Auslastungs-Tab, LP-Modal, Neues-Projekt-Modal │ │ ├── gantt.js # GANTT-Diagramm (buildGanttHtml, openProjectPlan), geshared │ │ ├── showmode.js # Show-Mode (Präsentationsmodus) │ │ ├── tabs-auth.js # showTab, confirmPassword (SHA256-Passwortschutz) │ │ ├── pdf.js # PDF-Export (pdfmake, A3 quer) │ │ └── init.js # renderAll/initUiState + Seiteneinstieg (nur Test.html) │ ├── project-plan.html # Gantt/TODO planning view │ ├── js/plan/ # planning modules (nur von project-plan.html geladen) │ │ ├── plan-state.js # PlanApp-Zustand, Datenladepath, savePlan, Toasts │ │ ├── plan-build-gantt.js # buildGanttHtml-Erweiterung (TODO- und Meilensteinzeilen) │ │ ├── plan-gantt.js # renderPlanGantt, Abhängigkeitslinien, Zoom, Ressourcen-Load │ │ ├── plan-drag.js # GANTT-Balken-Drag/Resize + TODO-/Meilenstein-Zeilen-Drag │ │ ├── plan-modals.js # TODO-, Meilenstein- und Abwesenheits-Modals │ │ └── plan-schedule.js # Kritischer Pfad, Auto-Schedule, Mail-Link │ ├── styles.css │ └── dein_bild.ico └── sessions/ # data; bind-mounted into Docker container ├── ELT/ HLS/ ARCH/ # one folder per department ``` ## Running ```bash npm install npm start # http://localhost:3003, or PORT=3004 if occupied docker compose up --build # Docker variant (compose file is at repo root) ``` - PORT env var overrides default 3003 in `server.js`. - Frontend must be served over HTTP: `baseUrl()` in `js/server.js` uses `window.location.origin` or falls back to `http://localhost:3003` when opened via `file://` (then only seed/demo data loads). - Check `/health` returns `{ok:true}` after starting. ## Server API (`server.js`) - `GET /` → `Test.html`; `GET /health`. - `GET /load-all?department=` → `{sessions:[{filename,content}], people}` with `_people.csv` content in `people`; sessions sorted by filename. - `POST /save-csv {filename, csv, department}` → writes UTF-8 BOM CSV. - `POST /delete-csv {filename, department}`. - Valid departments hard-coded as `ELT|HLS|ARCH` in `server.js` (`VALID_DEPARTMENTS`); anything else silently falls back to `ELT`. Same set in `DEPARTMENTS` in `js/globals.js`. - `safeName()` strictly validates filenames (path traversal protection); static assets get `Cache-Control: no-store`. - JSON body limit is 2 MB. ## CSV format - Delimiter `;`, UTF-8 with BOM. Hand-editing is possible but risky; the parser reconstructs objects from the fixed column layout. - Week files `