From 4e083bee73a395feac8c42b243ad121b50795f23 Mon Sep 17 00:00:00 2001 From: Erik Dunin Date: Fri, 14 Aug 2026 15:03:24 +0200 Subject: [PATCH 1/5] =?UTF-8?q?Unn=C3=B6tige=20Datein=20gel=C3=B6scht.=20D?= =?UTF-8?q?B=20normalisiert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 10244 -> 0 bytes .gitignore | 7 + AGENTS.md | 118 +- Docker/Dockerfile | 6 +- README.md | 43 +- public/.DS_Store | Bin 6148 -> 0 bytes public/Test.html | 3 +- public/js/.DS_Store | Bin 6148 -> 0 bytes public/js/board/board.js | 4 +- public/js/csv.js | 351 ---- public/js/gantt.js | 4 +- public/js/plan/plan-drag.js | 10 +- public/js/plan/plan-state.js | 41 +- public/js/projects/projects.js | 7 +- public/js/server.js | 48 +- public/js/store.js | 65 +- public/js/utils.js | 17 +- public/js/weeks.js | 20 +- public/main.v2.js | 3279 -------------------------------- public/project-plan.html | 3 +- public/project-plan.js | 1528 --------------- server.js | 827 +++++++- sessions/.DS_Store | Bin 10244 -> 0 bytes sessions/ARCH/KW_32___2026.csv | 8 - sessions/ARCH/_people.csv | 8 - sessions/ELT/KW_30___2026.csv | 9 - sessions/ELT/KW_31___2026.csv | 33 - sessions/ELT/KW_33___2026.csv | 33 - sessions/ELT/_people.csv | 14 - sessions/HLS/KW_30___2026.csv | 9 - sessions/HLS/KW_32___2026.csv | 11 - sessions/HLS/_people.csv | 7 - 32 files changed, 971 insertions(+), 5542 deletions(-) delete mode 100644 .DS_Store create mode 100644 .gitignore delete mode 100644 public/.DS_Store delete mode 100644 public/js/.DS_Store delete mode 100644 public/js/csv.js delete mode 100644 public/main.v2.js delete mode 100644 public/project-plan.js delete mode 100644 sessions/.DS_Store delete mode 100644 sessions/ARCH/KW_32___2026.csv delete mode 100644 sessions/ARCH/_people.csv delete mode 100644 sessions/ELT/KW_30___2026.csv delete mode 100644 sessions/ELT/KW_31___2026.csv delete mode 100644 sessions/ELT/KW_33___2026.csv delete mode 100644 sessions/ELT/_people.csv delete mode 100644 sessions/HLS/KW_30___2026.csv delete mode 100644 sessions/HLS/KW_32___2026.csv delete mode 100644 sessions/HLS/_people.csv diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index fb9a51a50e60ce0a2ca56072c78e78723882d0b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMYitx%6uxI#+BF89$lzB#1&d72qLg;7X(TvvVGAabsy7q?Ceb4ncW2% zVhJ%Ks6UMQw;1)OU{HKULVP6n!xuIfi3ymPh$fnt@CP;MxpQaB&XyAY@c1#anK}2K zd(OG%esj*9d+!oLpdl5nCB#n%p?EVYOZd3K#oF0D?h+i%Y@~qtMC+>!$Be|_I7yG; zA>bk4A>bk4A>bi!w;+JuYYXXwadVv-m!NSr9H-U(?OFOloRo?20@pJDruXD4A?_he!zmp^>cDIy{C zBt`~^LXvK8gp=rvt3B5jx?#+hJeljBOeAvyKO~}aL`V-w*rgQF&?nR7(}GK1qfZmc z=K42sqAZKmP2{ip`hVnIem9^e44*-gB2n~JC9!D69CYI4{pg^knpRECc@PQ;ClwXb zVp>8U3-=qDuobaVWg**7$_{K1t0|BAZ00|Ecgn&mYCf8DCO0|!Jpy?WW&ojn6uLN|`s zUK4OWDP#(-k3Em(kI999$;jk!?Pj`>kGY^BJLU`7F^iK+q$yHcdq=0#)v3k|J*@6m zdgM|Q2fhWXJCaHo2iy@ev{XVjd*rfMM2n@gh^5qP8WTodsToTenzq9*RZBJWU7eP) z*UB1lHFb8GM$&4ujrGWK%2akLXiH5iA+(65%2{tMgUpQCt|U#Q)xjD*c=7nunX~6D zShB2c&HBbinp#Fn<+Ad7rb$v4qO4nLuc{>5GHTrF-xV=qiXK<>zK*nNs!>g8)guX| z3@(b|Xt`Wg>Z|b0qH;CuOhwfvQ>wMk=1OyYeo;O}cgNA0W+Tol#<~1l-@TM}Gk#-I z!6#=+i+uNqa)h>;2n06~kd}(FDYgz^C~(zUX$6(zVw)C;DjH|4l2%i>N$g1T5pw2Q zX&o(tfY^zLl?fb=$=N|)1C`IxJ*@9-5z}fJRP?M@LEk1yyUhMbQfbLxEM_&fQfj|L zf>>=!!X?OsLzLQL)FtNMm|E$6F@#ksaTy2yz1Z*UaUUT z8?;Lg95$K4=U)8fxWOFhTtF^fury|ya2Dj z2pogg;B|Nt-i7zz1NacWfOGI2jKW2@48Ou}@Q*M_C=!Z=GNDpZ|7Tn%=#)SXU(1?RkdMmD0?SLRk@gD0Uc%1^X5xc@+8b2 zUR}5dt3{YOyn272s!A3xVR^Ntwn~xsmTe57C6;ElEa1N-7sw@YnOq@Pp$JMa%&TBAEQLA@?@h27nqV6=V~BS`7j)ZU z-iJZ{1Pp)$X$!?W-ryaX@X;r^-}?r*?xH~}Z&Z8!y|;S78NpTcMG zIeZ1*!zK6~{>TgK?b(3l6#mT*>)a3ZH^$F_YkX1T3jN$A%|tS;53*$c2jjAl4kvZZ z(EG4|mU0vqUbv*dpNbQPp0~IlnZIu&lk4l1s`BijVw|m9e{Uw|@)=*6cXaE9^LavBPr?73}t)!yD$*R!2Qs9VtJ}zvX`hc>8~E|9=Nh*Y1Y>|9>To Bbs+!% diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec99bcc --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# SQLite-Datenbank (Laufzeitartefakt in sessions/) +sessions/*.db +sessions/*.db-wal +sessions/*.db-shm + +# macOS-Artefakte +.DS_Store diff --git a/AGENTS.md b/AGENTS.md index 093811d..46d0fab 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,39 +4,38 @@ 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/`. +step, no bundler, no tests. Data is persisted in a SQLite database +(`node:sqlite`, needs Node >= 22.13) at `sessions/projektuebersicht.db`. 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 + (`globals`, `utils`, `ui`, `date-picker`, `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 +All UI strings/comments are German. Preserve German in user-facing text. ## File structure ``` . -├── server.js # Express server + CSV API +├── server.js # Express server + SQLite API ├── package.json # deps: express, cors only ├── docker-compose.yml # at repo ROOT; build context ., dockerfile Docker/Dockerfile -├── Docker/Dockerfile # node:20-alpine +├── Docker/Dockerfile # node:22-alpine (nötig für node:sqlite) ├── .dockerignore ├── .vscode/extensions.json ├── public/ │ ├── Test.html # main app (served at /) │ ├── js/ # shared modules (classic scripts, global fns) │ │ ├── globals.js # Konstanten (LPHS, ROLES, LPH-Farben, DEPARTMENTS) + db/currentDepartment -│ │ ├── utils.js # esc, uid, Datum-/Differenz-Helfer, personIdForName, peopleByRole, assignKey, weekSortKey-Quelle +│ │ ├── utils.js # esc, uid, Datum-/Differenz-Helfer, personIdForName, peopleByRole, assignKey, weekSortKey │ │ ├── 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 +│ │ ├── server.js # baseUrl, sendWeekToServer, sendPeopleToServer, blobToDataUrl │ │ ├── store.js # save/syncAllToServer, switchDepartment, load, seed │ │ ├── weeks.js # Wochen-Auswahl, -Erzeugung, -Klonen, Auto-Lock, -Löschung │ │ ├── gantt.js # GANTT-Diagramm (buildGanttHtml, openProjectPlan), geshared @@ -62,8 +61,8 @@ user-facing text. │ │ └── 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 +└── sessions/ # SQLite-DB; bind-mounted into Docker container + └── projektuebersicht.db # node:sqlite database (WAL mode) ``` ## Running @@ -93,31 +92,55 @@ docker compose up --build # Docker variant (compose file is at repo root) reads/writes these routes via `applyUrlRoute()`/`updateRouteUrl()` in `js/ui.js` and all static assets in the HTML use **absolute** paths (`/js/...`, `/styles.css`) so they resolve on nested routes. -- `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}`. +- `GET /load-all?department=` → `{weeks:[weekObj], people:[personObj]}` with the + global people list in `people`; weeks are full JSON week objects (id, label, + date, locked, people, attendance, projects), sorted by label. +- `POST /save-week {department, week}` → upserts one week (JSON object, keyed by + department + label). Used by `sendWeekToServer()`. +- `POST /save-people {department, people}` → replaces the department's global + people list (JSON array). +- `POST /delete-week {department, label}` → deletes the week; missing label + yields 400, missing week tolerates with `deleted:false`. - 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`. +- Static assets get `Cache-Control: no-store`. - JSON body limit is 2 MB. -## CSV format +## Persistence (SQLite) -- Delimiter `;`, UTF-8 with BOM. Hand-editing is possible but risky; the parser - reconstructs objects from the fixed column layout. -- Week files `