134 lines
5.6 KiB
Markdown
134 lines
5.6 KiB
Markdown
# AGENTS.md
|
|
|
|
## File structure
|
|
|
|
```
|
|
.
|
|
├── server.js # Express server with API endpoints
|
|
├── package.json # Dependencies (express, cors)
|
|
├── public/
|
|
│ ├── Test.html # Root HTML file (served at /)
|
|
│ ├── main.v2.js # Complete frontend client app
|
|
│ └── styles.css # UI styles
|
|
├── Docker/
|
|
│ └── Dockerfile # Node.js Alpine image
|
|
├── docker-compose.yml # Docker service definition
|
|
└── sessions/ # Data directory (bind-mounted in Docker)
|
|
├── ELT/ # Elektro department
|
|
├── HLS/ # HLS department
|
|
└── ARCH/ # Architektur department
|
|
```
|
|
|
|
## Overview
|
|
|
|
Single-page app for tracking engineering projects across weekly sessions
|
|
("Sitzungen"). Vanilla JS/HTML/CSS frontend (`public/`) + Node.js/Express server
|
|
(`server.js`). No build step, no bundler. Data is persisted as CSV files under
|
|
`sessions/`.
|
|
|
|
## Running
|
|
|
|
- `npm install` then `npm start` (executes `node server.js`).
|
|
- Or with Docker: `docker compose -f Docker/docker-compose.yml up --build`.
|
|
- Server runs on `PORT` env var or defaults to `3003`; serves `public/Test.html`
|
|
as root and API under `/load-all`, `/save-csv`, `/delete-csv`.
|
|
- Frontend assumes the API lives at `window.location.origin`, falling back to
|
|
`http://localhost:3003` when opened as a local file. Opening `Test.html`
|
|
directly without a server will load seed/demo data.
|
|
|
|
## Operations
|
|
|
|
### Local
|
|
```bash
|
|
npm install
|
|
npm start
|
|
```
|
|
Access at `http://localhost:3003` (or `PORT=3004` if occupied).
|
|
|
|
### Docker
|
|
```bash
|
|
docker compose -f Docker/docker-compose.yml up --build
|
|
```
|
|
Access at `http://localhost:3003` (or override with `PORT=3004`).
|
|
|
|
## CSV format
|
|
|
|
- Delimiter: semicolon (`;`)
|
|
- Encoding: UTF-8 with BOM (`\ufeff`)
|
|
- Structure:
|
|
- `sessions/<DEPT>/` contains department data
|
|
- Week files: `<Label>.csv` (e.g., `KW_30___2026.csv`)
|
|
- Global people: `_people.csv` with columns `NAME;Rollen;Voller Name`
|
|
|
|
## Data layout
|
|
- Data is split by department: `sessions/ELT/`, `sessions/HLS/`, `sessions/ARCH/`.
|
|
Valid departments are hard-coded in `server.js` (`VALID_DEPARTMENTS`) and
|
|
`main.v2.js` (`DEPARTMENTS`). Unknown department values fall back to `ELT`.
|
|
- Each week is one CSV file named `<Label>.csv` with `;` delimiter and UTF-8 BOM.
|
|
- Each department has a global people list in `_people.csv` with columns
|
|
`NAME;Rollen;Voller Name`. New people are added globally and copied into the
|
|
current week. Historical weeks keep their own person copies so deleted global
|
|
people remain visible in old sessions.
|
|
- The app reads CSVs on startup via `/load-all`; `localStorage` is used only
|
|
for the last-selected department/tab UI state. Do not store data in
|
|
`localStorage`.
|
|
- Editing CSVs by hand is possible but risky; prefer the UI.
|
|
|
|
## Architecture notes
|
|
|
|
- Frontend is in `public/` (`Test.html`, `main.v2.js`, `styles.css`).
|
|
- `main.v2.js` is the entire client app loaded as a classic non-module `<script>`;
|
|
all functions are globals on `window`.
|
|
- State lives in `let db = { weeks: [], currentWeek, globalPeople: {} }`.
|
|
- Each week object has `projects` (with `assign`, `lph`, `group`, `status`,
|
|
`order`) and `people` with session-local copies.
|
|
- `save()` schedules `syncAllToServer()` debounced by 500 ms; this writes **all**
|
|
weeks plus the global `_people.csv` to the server, not just the changed one.
|
|
- Weeks are sorted by calendar week extracted from the label (`KW XX / YYYY`),
|
|
not alphabetically.
|
|
- `applyAutoLock()` locks every week except the chronologically last one after
|
|
load/clone/new-week, so historical weeks are read-only unless explicitly
|
|
unlocked.
|
|
- Person IDs are derived from the person's abbreviation/name to stay stable
|
|
across reloads (`personIdForName` in `main.v2.js`).
|
|
|
|
## Docker
|
|
|
|
- Dockerfile uses `node:20-alpine` as base image.
|
|
- Copies only `package.json/package-lock.json` first (`npm ci --production`), then server files.
|
|
- Excludes `Docker/`, `node_modules/`, `.git`, `.gitignore` via `.dockerignore`.
|
|
- Runs as non-root `node` user; `/app/sessions` bind-mounted from host `./sessions`.
|
|
- HEALTHCHECK on `/health` endpoint; service restarts on failure (`unless-stopped`).
|
|
- Frontend must be served via HTTP (not `file://`) for CORS to work.
|
|
|
|
## Security / auth quirk
|
|
|
|
- `projects` and `people` tabs plus week deletion are gated by a password modal.
|
|
The check compares `CryptoJS.SHA256(input)` to `PROTECTED_PASSWORD_HASH` in
|
|
`main.v2.js`. This is client-side only and **not real security**. CryptoJS is
|
|
loaded from a CDN (`cdnjs.cloudflare.com`) in `Test.html`, so the password
|
|
gate needs internet access.
|
|
- User-provided status HTML is sanitized on render (small tag/attribute
|
|
whitelist) to mitigate XSS while keeping formatting options.
|
|
- Filenames sent to `/save-csv` and `/delete-csv` are strictly validated server
|
|
side to prevent path traversal.
|
|
|
|
## Conventions
|
|
|
|
- UI strings, comments, and CSV content are German. Preserve German in
|
|
user-facing text.
|
|
- No linter, formatter, typecheck, or test suite is configured. Verify changes
|
|
by running the server and exercising the relevant tab in the browser.
|
|
- This is **not** a git repo. Don't assume git workflows.
|
|
- Edit `main.v2.js` functions in place; the file is intentionally one large script
|
|
with German header comments per section. Match that style.
|
|
|
|
## Testing & verification
|
|
|
|
- No automated test suite exists. Manual verification only:
|
|
- Start server (`npm start` or Docker)
|
|
- Open `http://localhost:3003`
|
|
- Check `/health` endpoint returns `{ok:true}`
|
|
- Exercise relevant tab in browser (Board, Projects, People)
|
|
- Verify CSV persistence in `sessions/` directory
|