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:
109
CLAUDE.md
Normal file
109
CLAUDE.md
Normal 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`
|
||||
Reference in New Issue
Block a user