# VigilanzaTurni - Sistema Gestione Turni per Istituti di Vigilanza ## Overview VigilanzaTurni is a professional 24/7 shift management system designed for security companies. It offers multi-role authentication (Admin, Coordinator, Guard, Client), comprehensive guard and site management, 24/7 shift planning, a live operational dashboard with KPIs, reporting for worked hours, and a notification system. The system supports multi-location operations (Roccapiemonte, Milano, Roma) managing 250+ security personnel across different branches. The project aims to streamline operations and enhance efficiency for security institutes. ## User Preferences - Interfaccia in italiano - Dark mode di default - Design operativo e funzionale (non decorativo) - Focus su efficienza e densità informativa - **Testing**: Tutti i test vengono eseguiti ESCLUSIVAMENTE sul server esterno (vt.alfacom.it) con autenticazione locale (non Replit Auth) ## ⚠️ CRITICAL: Date/Timezone Handling Rules **PROBLEMA RICORRENTE**: Quando si assegna una guardia per il giorno X, appare assegnata al giorno X±1 a causa di conversioni timezone. **REGOLE OBBLIGATORIE** per evitare questo bug: 1. **MAI usare `parseISO()` su date YYYY-MM-DD** - ❌ SBAGLIATO: `const date = parseISO("2025-10-20")` → converte in UTC causando shift - ✅ CORRETTO: `const [y, m, d] = "2025-10-20".split("-").map(Number); const date = new Date(y, m-1, d)` 2. **Costruire Date da componenti, NON da stringhe ISO** ```typescript // ✅ CORRETTO - date components (no timezone conversion) const [year, month, day] = startDate.split("-").map(Number); const shiftDate = new Date(year, month - 1, day); const shiftStart = new Date(year, month - 1, day, startHour, startMin, 0, 0); // ❌ SBAGLIATO - parseISO o new Date(string ISO) const date = parseISO(startDate); // converte in UTC! const date = new Date("2025-10-20"); // timezone-dependent! ``` 3. **Validazione date: usare regex, NON parseISO** ```typescript // ✅ CORRETTO const dateRegex = /^\d{4}-\d{2}-\d{2}$/; if (!dateRegex.test(dateStr)) { /* invalid */ } // ❌ SBAGLIATO const parsed = parseISO(dateStr); if (!isValid(parsed)) { /* invalid */ } ``` 4. **File da verificare sempre**: `server/routes.ts` - tutte le route che ricevono date dal frontend 5. **Testare sempre**: Assegnare guardia giorno X → verificare appaia nel giorno X (non X±1) **RIFERIMENTI FIX**: Vedere commit "Fix timezone bug in shift creation" - linee 1148-1184, 615-621, 753-759 in server/routes.ts ## System Architecture ### Stack Tecnologico - **Frontend**: React + TypeScript + Tailwind CSS + Shadcn UI - **Backend**: Express.js + TypeScript - **Database**: PostgreSQL (Neon) with Drizzle ORM - **Autenticazione**: Replit Auth (OIDC) - **State Management**: TanStack Query v5 - **Routing**: Wouter ### Design System - **Font Principale**: Inter (sans-serif) - **Font Monospace**: JetBrains Mono - **Colori**: Primary Blue, Status Green, Orange, Red, Gray for various operational states. - **Tema**: Dark mode by default, with light mode support. - **Componenti**: Shadcn UI with an operational design. ### Database Schema The database includes core tables for `users`, `guards`, `certifications`, `sites`, `shifts`, `shift_assignments`, and `notifications`. Advanced scheduling and constraints are managed via `guard_constraints`, `site_preferences`, `contract_parameters`, `training_courses`, `holidays`, `holiday_assignments`, `absences`, and `absence_affected_shifts`. All tables include appropriate foreign keys and unique constraints to maintain data integrity. **Recent Schema Updates (October 2025)**: - Service types now include specialized parameters: `fixedPostHours` (ore presidio fisso), `patrolPassages` (numero passaggi pattuglia), `inspectionFrequency` (frequenza ispezioni), `responseTimeMinutes` (tempo risposta pronto intervento) - Sites include service schedule fields: `serviceStartTime` and `serviceEndTime` (formato HH:MM) - **Contract Management**: Sites now include contract fields: `contractReference` (codice contratto), `contractStartDate`, `contractEndDate` (date validità contratto in formato YYYY-MM-DD) - Sites now reference service types via `serviceTypeId` foreign key; `shiftType` is optional and can be derived from service type - **Multi-Location Support**: Added `location` field (enum: roccapiemonte, milano, roma) to `sites`, `guards`, and `vehicles` tables for complete multi-sede resource isolation **Recent Features (October 17-18, 2025)**: - **Multi-Sede Operational Planning**: Redesigned operational planning workflow with location-first approach: 1. Select sede (Roccapiemonte/Milano/Roma) - first step with default value 2. Select date 3. View uncovered sites filtered by selected sede 4. Select site → view available resources (guards and vehicles) filtered by sede 5. Assign resources and create shift - **Location-Based Filtering**: Backend endpoints use INNER JOIN with sites table to ensure complete resource isolation between locations - guards/vehicles in one sede remain available even when assigned to shifts in other sedi - **Site Management**: Added sede selection in site creation/editing forms with visual badges showing location in site listings - **Planning Fissi (October 18, 2025)**: New weekly planning overview feature showing all sites × 7 days in table format: - **Contract filtering**: Shows only sites with active contracts in the week dates (`contractStartDate <= weekEnd AND contractEndDate >= weekStart`) - Backend endpoint `/api/general-planning?weekStart=YYYY-MM-DD&location=sede` with complex joins and location filtering - Automatic missing guards calculation: `ceil(totalShiftHours / maxHoursPerGuard) × minGuards - assignedGuards` (e.g., 24h shift, 2 guards min, 9h max = 6 total needed) - **Weekly summary**: Shows total guards needed, guards assigned (counting slots, not unique people), and guards missing for the entire week - Table cells display: assigned guards with hours, vehicles, missing guards badge (if any), shift count, total hours - Interactive cells with click handler opening detail dialog - Dialog shows: shift count, total hours, guard list with hours and badge numbers, vehicle list, missing guards warning with explanation - **Direct Shift Creation from Dialog**: Users can now create multi-day shifts directly from the Planning Generale dialog: - Select guard from dropdown showing name + weekly available hours (max 45h - assigned hours) - Specify number of consecutive days (1-7) - Backend endpoint `POST /api/general-planning/shifts` with atomic transaction using `db.transaction()` - all shifts created or none (rollback on error) - Validates contract dates, site and guard existence before transaction - Automatically creates shifts spanning multiple days with correct time ranges from site service schedule - TanStack Query mutation with cache invalidation for real-time planning grid updates - "Modifica in Pianificazione Operativa" button in dialog navigates to operational planning page with pre-filled date/location parameters - Week navigation (previous/next week) with location selector - Operational planning page now supports query parameters (`?date=YYYY-MM-DD&location=sede`) for seamless integration **Recent Bug Fixes (October 17-18, 2025)**: - **Operational Planning Date Handling**: Fixed date sanitization in `/api/operational-planning/uncovered-sites` and `/api/operational-planning/availability` endpoints to handle malformed date inputs (e.g., "2025-10-17/2025-10-17"). Both endpoints now validate dates using `parseISO`/`isValid` and return 400 for invalid formats. - **Checkbox Event Propagation**: Fixed double-toggle bug in operational planning resource selection by wrapping vehicle and guard checkboxes in `
e.stopPropagation()}>` to prevent Card onClick from firing when clicking checkboxes. - **Multi-Sede Resource Isolation**: Fixed critical bug where resources from different sedi were incorrectly marked as unavailable due to global shift queries. Now both availability and uncovered-sites endpoints filter shifts by location using JOIN with sites table. - **QueryKey Cache Invalidation**: Fixed queryKey structure from single-string to hierarchical array with custom queryFn to enable targeted cache invalidation by location and date while preventing URL concatenation errors. - **apiRequest Parameter Order (October 18, 2025)**: Fixed inverted parameters bug in Planning Generale shift creation mutation. Changed `apiRequest(url, method, data)` to correct signature `apiRequest(method, url, data)` matching queryClient.ts function definition. ### API Endpoints Comprehensive RESTful API endpoints are provided for Authentication, Users, Guards, Sites, Shifts, and Notifications, supporting full CRUD operations with role-based access control. ### Frontend Routes Key frontend routes include `/`, `/guards`, `/sites`, `/shifts`, `/reports`, `/notifications`, and `/users`, with access controlled by user roles. ### User Roles - **Admin**: Full access to all functionalities, managing guards, sites, shifts, and reports. - **Coordinator**: Shift planning, guard assignment, operational site management, and reporting. - **Guard**: View assigned shifts, future time-punching, notifications, and personal profile. - **Client**: View assigned sites, service reporting, and KPIs. ### Key Features - **Dashboard Operativa**: Live KPIs (active shifts, total guards, active sites, expiring certifications) and real-time shift status. - **Gestione Guardie**: Complete profiles with skill matrix (armed, fire safety, first aid, driver's license), certification management with automatic expiry, and unique badge numbers. - **Gestione Siti/Commesse**: Service types with specialized parameters (fixed post hours, patrol passages, inspection frequency, response time) and minimum requirements (guard count, armed, driver's license). Sites include service schedule (start/end time), contract management (reference code, validity period with start/end dates), and location/sede assignment. Contract status is visualized with badges (active/expiring/expired) and enforces shift creation only within active contract periods. - **Pianificazione Operativa Multi-Sede**: Location-aware workflow for shift assignment: 1. Select sede (Roccapiemonte/Milano/Roma) → filters all subsequent data by location 2. Select date → view uncovered sites with coverage status (sede-filtered) 3. Select site → view available resources (guards and vehicles matching sede and requirements) 4. Assign resources → create shift with atomic guard assignments and vehicle allocation - **Pianificazione Turni**: 24/7 calendar, manual guard assignment, basic constraints, and shift statuses (planned, active, completed, cancelled). - **Reportistica**: Total hours worked, monthly hours per guard, shift statistics, and data export capabilities. - **Advanced Planning**: Management of guard constraints (preferences, max hours, rest days), site preferences (preferred/blacklisted guards), contract parameters, training courses, holidays, and absences with substitution system. ## External Dependencies - **Replit Auth**: For OpenID Connect (OIDC) based authentication. - **Neon**: Managed PostgreSQL database service. - **Tailwind CSS**: For utility-first CSS styling. - **Shadcn UI**: For UI components. - **Zod**: For schema validation. - **TanStack Query**: For data fetching and state management. - **Wouter**: For client-side routing. - **date-fns**: For date manipulation and formatting. - **PM2**: Production process manager for Node.js applications. - **Nginx**: As a reverse proxy for the production environment. - **Let's Encrypt**: For SSL/TLS certificates. - **GitLab CI/CD**: For continuous integration and deployment.