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>
5.1 KiB
5.1 KiB
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 dataPOST /api/files— Create new file{ name, data }PUT /api/files/:id— Update file{ name?, data }DELETE /api/files/:id— Delete filePOST /api/files/import-excel— Upload .xlsx, parse to JSON, create fileGET /api/files/:id/export-excel— Download as Excel using templateGET /api/files/diff/:id1/:id2— Cell-by-cell diff between two files
Data Model
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.tsasHOLIDAYSMap - 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
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
./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
- Station list — Change station codes/names in
data.jsonandSTATION_ROWSinexport_excel.pyandserver.js - Excel template — Replace
public/template.xlsxwith TKB's schedule format - Holidays — Update
HOLIDAYSMap inuseScheduleState.ts - Constraints — Adjust rules in
constraints.ts(may differ for tunnels) - Phase labels — Update
PHASE_LABELSinToolbar.tsxandgetCellColorinScheduleTable.tsx - Login credentials — Change in
Login.tsx - App title — Change in
index.htmland header inApp.tsx - Port — Change
PORTinserver.js - Deploy target — Update
REMOTEindeploy.sh