feat: TKB shift scheduler — personnel shift planning web app

Full rewrite of METRO HMG for TKB tunnel department:
- People-based grid (18 TKB + 5 IT), year-long calendar
- Color-coded shift values (4/6/8/12/A/B/D/N/U/O)
- Drag-and-drop cells, multi-cell selection (click/ctrl/shift/drag)
- Right-click context menu with color palette
- Tunnel closure + Metro + D8 info rows (toggleable)
- Czech holidays highlighted with names
- PDF export (2-page A4 landscape, DejaVu font for Czech chars)
- Improvement proposals system
- Sticky headers (vertical + horizontal scroll)
- Cell value filter toggles in legend

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Docker Config Backup
2026-04-02 09:48:38 +02:00
commit b4158d687f
47 changed files with 14185 additions and 0 deletions

109
CLAUDE.md Normal file
View File

@@ -0,0 +1,109 @@
# TKB HMG — Tunnel Maintenance Schedule Manager
This is a spinoff of the METRO HMG project (Prague metro station maintenance scheduling). Adapted for Prague car tunnels (TKB) maintenance department.
## Origin
Copied from `/home/klas/Prace/METRO/web/` — a fully working schedule management web app.
## Architecture
### Tech Stack
- **Frontend**: React 19 + TypeScript + Vite + Tailwind CSS
- **Backend**: Express (Node.js), file-based JSON storage
- **Excel**: openpyxl (Python, server-side export/import), xlsx (client-side import)
- **Port**: 3080 (change in `web/server.js`)
### Key Files
```
web/
├── server.js # Express API server (ES modules)
├── export_excel.py # Python: JSON → Excel using template
├── import_excel.py # Python: Excel → JSON
├── deploy.sh # Deploy script (rsync to remote)
├── watch-deploy.js # Auto-deploy on file changes
├── public/
│ └── template.xlsx # Excel template for export formatting
├── src/
│ ├── App.tsx # Main app: login → file manager → editor
│ ├── FileManager.tsx # File list, upload, compare, delete
│ ├── ScheduleTable.tsx # Main schedule grid (largest component)
│ ├── useScheduleState.ts # State management: stations, obstacles, comments
│ ├── useDragBlock.ts # Drag-and-drop logic for blocks and s/v cells
│ ├── blockParser.ts # Parse k+14+Z indivisible blocks
│ ├── constraints.ts # Validation: max k/night, max 5 evaluations
│ ├── ContextMenu.tsx # Right-click menu (obstacles, comments, s/v)
│ ├── Toolbar.tsx # Filter toggles, save, undo, compare banner
│ ├── Login.tsx # Simple client-side auth
│ ├── excelIO.ts # Client-side Excel import (xlsx library)
│ ├── types.ts # All TypeScript interfaces
│ └── data.json # Default/fallback schedule data
└── schedules/ # Server-stored JSON schedule files
```
### API Endpoints (server.js)
- `GET /api/files` — List all schedule files (metadata only)
- `GET /api/files/:id` — Load single file with full data
- `POST /api/files` — Create new file `{ name, data }`
- `PUT /api/files/:id` — Update file `{ name?, data }`
- `DELETE /api/files/:id` — Delete file
- `POST /api/files/import-excel` — Upload .xlsx, parse to JSON, create file
- `GET /api/files/:id/export-excel` — Download as Excel using template
- `GET /api/files/diff/:id1/:id2` — Cell-by-cell diff between two files
### Data Model
```typescript
ScheduleData {
dayIndex: DayInfo[] // Array of day metadata (idx, day, month, year, week, weekend)
stations: Station[] // 27 stations, each with data: Record<string, CellValue>
obstacles?: Obstacle[] // Per-cell blocking issues (hatched red overlay)
dayComments?: DayComment[] // DEN row comments (hatched blue column overlay)
cellComments?: CellComment[] // Per-cell comments (blue triangle indicator)
}
```
Cell values: `s` (physical servers), `v` (virtual servers), `k` (on-site work), `14` (evaluation days), `Z` (processing)
### Key Concepts
- **dayIndex.idx** values are NOT array indices — they're offsets from the Excel column mapping (col = idx + 7)
- **Indivisible block**: k + 14×"14" + 5×"Z" = 20 cells that move as one unit
- **s and v cells** are independent, can be dragged separately, can have multiple per station
- **Holidays** are hardcoded in `useScheduleState.ts` as `HOLIDAYS` Map
- **Constraints**: max 1 k/night, max 5 stations in "14"+"Z" simultaneously
- **Ghost blocks**: comparison overlay shows old positions as dashed semi-transparent blocks
### Running
```bash
cd web
npm install
npx vite build
node server.js # Production: serves dist/ on port 3080
# OR
npm run dev # Dev: Vite HMR on port 5173, proxies /api to 3080
```
### Auth
- Username: `metro`, Password: `colsys` (client-side only, in Login.tsx)
- Change these for TKB deployment
### Deploying to Remote
```bash
./deploy.sh # Builds, rsyncs to remote, restarts pm2
```
Edit `deploy.sh` to set the remote host. Uses pm2 for process management.
### Excel Template
- `public/template.xlsx` — the original Excel schedule format
- Export writes data into this template, preserving formatting
- Replace with TKB's own template
## What to Customize for TKB
1. **Station list** — Change station codes/names in `data.json` and `STATION_ROWS` in `export_excel.py` and `server.js`
2. **Excel template** — Replace `public/template.xlsx` with TKB's schedule format
3. **Holidays** — Update `HOLIDAYS` Map in `useScheduleState.ts`
4. **Constraints** — Adjust rules in `constraints.ts` (may differ for tunnels)
5. **Phase labels** — Update `PHASE_LABELS` in `Toolbar.tsx` and `getCellColor` in `ScheduleTable.tsx`
6. **Login credentials** — Change in `Login.tsx`
7. **App title** — Change in `index.html` and header in `App.tsx`
8. **Port** — Change `PORT` in `server.js`
9. **Deploy target** — Update `REMOTE` in `deploy.sh`