v1.0.0 - Gennaio 2025

Documentazione Tecnica

Architettura, API e guida tecnica per sviluppatori del Property Management System di CheckIn Facile.

Indice dei Contenuti

Naviga rapidamente verso la sezione che ti interessa.

Architettura del Sistema

Il PMS di CheckIn Facile segue un'architettura a tre livelli con separazione netta tra presentazione, logica di business e persistenza dati. Il sistema utilizza il Service Layer Pattern con manager specializzati per dominio.

Stack Tecnologico

Frontend FrameworkReact 18.x
State ManagementContext + Hooks
StylingTailwind CSS 3.x
RoutingReact Router 6.x
PersistenzalocalStorage / API
Build ToolVite 5.x

Diagramma Architetturale

┌─────────────────────────────────────────────────────────────────┐ │ PRESENTATION LAYER │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌────────────┐│ │ │ PMSDashboard│ │ Housekeeping│ │ Maintenance │ │ Calendar ││ │ │ Page │ │ Page │ │ Page │ │ Page ││ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └─────┬──────┘│ │ │ │ │ │ │ │ ┌──────┴───────────────┴───────────────┴──────────────┴──────┐ │ │ │ usePMS Hook │ │ │ │ (State Management & Business Logic Bridge) │ │ │ └──────────────────────────┬─────────────────────────────────┘ │ └─────────────────────────────┼───────────────────────────────────┘ │ ┌─────────────────────────────┼───────────────────────────────────┐ │ SERVICE LAYER │ │ ┌──────────────────────────┴─────────────────────────────────┐ │ │ │ PMSService │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │ Reservation │ │ Housekeeping│ │ Maintenance │ │ │ │ │ │ Manager │ │ Manager │ │ Manager │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │ Inventory │ │ StaffTask │ │ │ │ │ │ Manager │ │ Manager │ │ │ │ │ └─────────────┘ └─────────────┘ │ │ │ └────────────────────────────────────────────────────────────┘ │ └─────────────────────────────┼───────────────────────────────────┘ │ ┌─────────────────────────────┼───────────────────────────────────┐ │ DATA LAYER │ │ ┌──────────────────────────┴─────────────────────────────────┐ │ │ │ localStorage │ │ │ │ (Demo Mode - Sostituibile con API REST) │ │ │ └────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘

Flusso dei Dati

User Action → Component → usePMS Hook → PMSService → Manager → Storage
                                                                  ↓
User Feedback ← Component ← usePMS Hook ← Updated State ←──┘

Design Pattern Utilizzati

PatternUtilizzo
SingletonPMSService instance globale
Manager PatternSeparazione logica per dominio
Custom HookIntegrazione React con servizi
ObserverAggiornamenti reattivi dello stato
RepositoryAstrazione del layer di persistenza

Filosofia di Design

  1. Separazione delle Responsabilità — Servizi per la logica, hook per lo stato React, componenti per la presentazione.
  2. Scalabilità Orizzontale — L'architettura a manager permette di aggiungere moduli senza modificare codice esistente.
  3. Testabilità — Ogni manager può essere testato in isolamento.
  4. Flessibilità del Backend — localStorage per la demo, facilmente sostituibile con API REST.
  5. Internazionalizzazione Ready — Tutte le stringhe sono centralizzate in PMS_LABELS.

Struttura dei File

Il codice sorgente del PMS è organizzato seguendo una struttura modulare all'interno della directory src/.

src/ ├── services/ │ ├── pmsService.js # Core service con tutti i manager │ ├── pmsAnalyticsService.js # Metriche e KPI │ ├── pmsNotificationService.js # Sistema notifiche │ ├── pmsStaffManagementService.js # Gestione staff │ ├── pmsRatesService.js # Tariffe dinamiche │ ├── pmsGuestCRMService.js # CRM ospiti │ ├── pmsAttachmentsService.js # Gestione allegati │ └── pmsScheduledMaintenanceService.js # Manutenzione programmata │ ├── hooks/ │ └── usePMS.js # React hook per integrazione │ ├── pages/ │ ├── PMSDashboardPage.jsx # Dashboard principale │ ├── HousekeepingPage.jsx # Gestione pulizie │ ├── MaintenancePage.jsx # Gestione manutenzione │ ├── InventoryPage.jsx # Gestione inventario │ └── ReservationsCalendarPage.jsx # Calendario prenotazioni │ ├── context/ │ └── DataContext.jsx # Context esistente (integrazione) │ └── App.jsx # Route definitions

Nota: Il file pmsService.js contiene circa 1800+ righe di codice ed è il cuore dell'intero sistema PMS.

Core Service: pmsService.js

Il file pmsService.js contiene costanti, enumerazioni, 5 manager specializzati, la classe PMSService principale, il generatore di mock data e l'istanza singleton esportata.

Costanti e Enumerazioni

export const RESERVATION_STATUS = {
  CONFIRMED: 'confirmed',     // Prenotazione confermata
  CHECKED_IN: 'checked_in',   // Ospite arrivato
  CHECKED_OUT: 'checked_out', // Ospite partito
  CANCELLED: 'cancelled',     // Cancellata
  NO_SHOW: 'no_show',         // Non presentato
  PENDING: 'pending'           // In attesa
};

export const ROOM_STATUS = {
  CLEAN: 'clean',                     // Pulita e pronta
  DIRTY: 'dirty',                     // Da pulire
  CLEANING: 'cleaning',               // Pulizia in corso
  INSPECTED: 'inspected',             // Ispezionata
  OUT_OF_ORDER: 'out_of_order',       // Fuori servizio (guasto)
  OUT_OF_SERVICE: 'out_of_service'   // Fuori servizio (manutenzione)
};

export const MAINTENANCE_PRIORITY = {
  EMERGENCY: 'emergency', // Risoluzione immediata
  HIGH: 'high',           // Entro 24h
  MEDIUM: 'medium',       // Entro 48h
  LOW: 'low'              // Programmabile
};

ReservationManager

Gestisce l'intero ciclo di vita delle prenotazioni: creazione, aggiornamento, check-in, check-out, cancellazione e query avanzate.

class ReservationManager {
  // CRUD
  getAll()                    // Tutte le prenotazioni
  getById(id)                 // Per ID
  create(data)                // Crea nuova
  update(id, updates)         // Aggiorna
  delete(id)                  // Elimina

  // Query
  getByRoom(roomId)           // Per camera
  getByDateRange(start, end)  // Per range date
  getArrivals(date)           // Arrivi del giorno
  getDepartures(date)         // Partenze del giorno
  getInHouse()                // Ospiti in casa

  // Azioni
  checkIn(id, data)           // Esegue check-in
  checkOut(id, data)          // Esegue check-out
  cancel(id, reason)          // Cancella
  markNoShow(id)              // Segna no-show

  // Utilità
  isRoomAvailable(roomId, checkIn, checkOut, excludeId)
  getOccupancyRate(date)
}

HousekeepingManager

Gestisce task di pulizia, stato camere, assegnazioni e checklist digitali.

class HousekeepingManager {
  getTasks() / createTask(data) / completeTask(id, data)
  getRoomStatus(roomId) / updateRoomStatus(roomId, status)
  getTasksByAssignee(staffId) / getUrgentTasks()
  generateDailyTasks(date) / assignTask(taskId, staffId)
  getTaskChecklist(taskId) / updateChecklistItem(taskId, itemId, completed)
}

MaintenanceManager

Gestisce i ticket di manutenzione con workflow di stati, commenti e statistiche.

class MaintenanceManager {
  getTickets() / createTicket(data) / updateTicket(id, updates)
  startWork(id, technicianId) / completeWork(id, data)
  addComment(ticketId, comment) / getComments(ticketId)
  getOpenTickets() / getUrgentTickets()
  getStatistics(dateRange) / getAverageResolutionTime()
}

InventoryManager

Gestisce prodotti, scorte, movimenti di magazzino e generazione liste acquisti.

class InventoryManager {
  getProducts() / createProduct(data) / updateProduct(id, updates)
  addStock(productId, qty, notes) / removeStock(productId, qty, notes)
  getLowStockProducts() / getOutOfStockProducts()
  getMovements(productId) / getInventoryValue()
  generateShoppingList()
}

StaffTaskManager

Gestisce l'assegnazione dei compiti, notifiche e monitoraggio task per lo staff.

class StaffTaskManager {
  getTasks() / createTask(data) / completeTask(id, data)
  assignTask(taskId, staffId) / reassignTask(taskId, newStaffId)
  getTasksByStaff(staffId) / getOverdueTasks()
  sendTaskNotification(taskId) / sendReminder(taskId)
}

Servizi Avanzati

Oltre al core service, il sistema include servizi specializzati modulari e indipendenti che estendono le funzionalità del PMS.

Analytics Service

Fornisce metriche, KPI e analisi delle performance della struttura ricettiva.

import { analyticsService } from '../services/pmsAnalyticsService';

// Metriche principali
analyticsService.calculateOccupancyRate({ startDate, endDate, reservations, totalRooms });
analyticsService.calculateADR({ totalRevenue, roomNightsSold });
analyticsService.calculateRevPAR({ totalRevenue, availableRoomNights });
analyticsService.generatePerformanceReport({ startDate, endDate, ... });
MetricaFormulaUtilizzo
Occupancy Rate(Notti vendute / Notti disponibili) x 100Domanda e pricing
ADRRevenue totale / Notti venduteValore medio prenotazione
RevPARRevenue totale / Notti disponibiliPerformance complessiva
Cancellation RateCancellazioni / Totale prenotazioniRischio revenue

Notification Service

Gestisce notifiche e alert tramite canali multipli: in-app, email, SMS, push e WhatsApp.

import { notificationService, NOTIFICATION_TYPES } from '../services/pmsNotificationService';

notificationService.send({
  type: NOTIFICATION_TYPES.HOUSEKEEPING_ASSIGNED,
  recipient: 'staff-123',
  channel: 'in_app',
  data: { taskId: 'hk-456', roomName: 'Camera 101', priority: 'urgent' }
});

notificationService.getUnread('user-123');
notificationService.markAsRead('notification-123');

Staff Management Service

Gestisce staff, turni, competenze, carichi di lavoro e assegnazione automatica intelligente.

import { staffService } from '../services/pmsStaffManagementService';

staffService.getAvailableStaff({ date, department, skill });
staffService.calculateWorkload({ staffId, date });
staffService.autoAssign({ task, availableStaff, considerWorkload: true });
staffService.getPerformanceReport({ staffId, startDate, endDate });

Rates Service

Gestisce tariffe dinamiche con aggiustamenti stagionali, per giorno della settimana, sconti per durata soggiorno e pricing basato sull'occupazione.

import { ratesService } from '../services/pmsRatesService';

const pricing = ratesService.calculateStayPrice({
  roomType: 'double',
  checkIn: '2025-07-15',
  checkOut: '2025-07-22',
  guests: 2,
  currentOccupancy: 75,
  promoCode: 'SUMMER10'
});
// Result: { basePrice, seasonalAdj, losDiscount, finalPrice, breakdown[] }

Guest CRM Service

Profilo ospiti completo con storico soggiorni, preferenze, loyalty, segmentazione e campagne mirate.

import { guestCRMService } from '../services/pmsGuestCRMService';

guestCRMService.searchGuests({ query: 'Rossi', tags: ['high_value'] });
guestCRMService.getRecommendations('guest-001');
guestCRMService.segmentGuests({ criteria: 'total_spent' });
guestCRMService.sendCampaign({ segment: 'gold', template: 'loyalty_offer' });

Integrazione tra Servizi

I servizi lavorano insieme in workflow completi. Esempio: checkout automatico.

async function handleCheckout(reservationId) {
  // 1. Aggiornare stato prenotazione
  const reservation = pmsService.reservations.checkOut(reservationId);

  // 2. Creare task pulizia automatico
  const task = pmsService.housekeeping.createTask({
    roomId: reservation.roomId, type: 'checkout_clean'
  });

  // 3. Notificare housekeeping
  notificationService.send({ type: 'housekeeping_assigned', recipient: task.assignedTo });

  // 4. Aggiornare analytics e CRM
  analyticsService.recordCheckout({ reservationId });
  guestCRMService.updateStayHistory({ guestId: reservation.guestId });
}

React Hook: usePMS

L'hook usePMS è il bridge tra il servizio PMS e i componenti React. Gestisce inizializzazione, persistenza su localStorage, aggiornamenti reattivi e integrazione con il DataContext esistente.

import { useState, useEffect, useCallback } from 'react';
import { useData } from '../context/DataContext';
import { pmsService } from '../services/pmsService';

export const usePMS = () => {
  const { property, currentPropertyId } = useData();
  const [loading, setLoading] = useState(true);
  const [reservations, setReservations] = useState([]);
  const [housekeepingTasks, setHousekeepingTasks] = useState([]);
  const [maintenanceTickets, setMaintenanceTickets] = useState([]);
  const [inventory, setInventory] = useState([]);
  // ... inizializzazione e auto-save su localStorage

  return {
    loading, reservations, housekeepingTasks, maintenanceTickets, inventory,
    addReservation, updateReservation, checkIn, checkOut,
    addHousekeepingTask, completeHousekeepingTask,
    addMaintenanceTicket, addInventoryProduct,
    getDashboardOverview, getArrivals, getDepartures, // ...
  };
};

Utilizzo nei Componenti

import { usePMS } from '../hooks/usePMS';

const MyComponent = () => {
  const { loading, reservations, getArrivals, addReservation } = usePMS();

  if (loading) return <Spinner />;

  const todayArrivals = getArrivals(new Date());

  return <div>Arrivi Oggi: {todayArrivals.length}</div>;
};

Componenti e Pagine

Ogni pagina PMS è un componente React autonomo che utilizza l'hook usePMS per accedere a dati e metodi.

PMSDashboardPage /pms

Dashboard principale con panoramica di tutti i moduli: Quick Stats (KPI), arrivi e partenze del giorno, griglia stato camere, task housekeeping urgenti, alert manutenzione, prodotti sotto scorta.

HousekeepingPage /pms/housekeeping

Gestione completa pulizie: lista task con filtri (stato, priorità, assegnatario), vista griglia camere, creazione/modifica task, assegnazione staff, completamento con checklist, timeline attività.

MaintenancePage /pms/maintenance

Gestione ticket manutenzione: lista con filtri multipli, creazione con categoria e priorità, workflow stati (open → in_progress → completed), sistema commenti, storico interventi, statistiche risoluzione.

InventoryPage /pms/inventory

Gestione inventario: catalogo prodotti con categorie, gestione stock (carico/scarico), alert scorte basse, storico movimenti, generazione lista acquisti, report valore inventario.

ReservationsCalendarPage /pms/calendar

Calendario interattivo con drag & drop per spostare prenotazioni, resize per estendere soggiorni, color coding per stato, quick create su cella vuota, viste settimana/mese.

Routing

// In App.jsx
<Route path="/pms" element={<ProtectedRoute><PMSDashboardPage /></ProtectedRoute>} />
<Route path="/pms/housekeeping" element={<ProtectedRoute><HousekeepingPage /></ProtectedRoute>} />
<Route path="/pms/maintenance" element={<ProtectedRoute><MaintenancePage /></ProtectedRoute>} />
<Route path="/pms/inventory" element={<ProtectedRoute><InventoryPage /></ProtectedRoute>} />
<Route path="/pms/calendar" element={<ProtectedRoute><ReservationsCalendarPage /></ProtectedRoute>} />

Modelli Dati

Le interfacce TypeScript-style che descrivono la struttura dei dati principali del sistema.

Reservation

interface Reservation {
  id: string;
  propertyId: string;
  roomId: string;
  guestName: string;
  guestEmail?: string;
  guestPhone?: string;
  checkIn: string;          // ISO date
  checkOut: string;         // ISO date
  adults: number;
  children: number;
  totalPrice: number;
  status: ReservationStatus;
  source: ReservationSource;
  notes?: string;
  specialRequests?: string[];
  createdAt: string;
  updatedAt: string;
}

HousekeepingTask

interface HousekeepingTask {
  id: string;
  roomId: string;
  roomName: string;
  type: HousekeepingTaskType;     // checkout_clean | stay_over | deep_clean | ...
  priority: HousekeepingPriority;  // urgent | high | normal | low
  status: TaskStatus;
  assignedTo?: string;
  scheduledDate: string;
  estimatedDuration: number;      // minuti
  checklist: ChecklistItem[];
  startedAt?: string;
  completedAt?: string;
}

interface ChecklistItem {
  id: string;
  task: string;
  completed: boolean;
}

MaintenanceTicket

interface MaintenanceTicket {
  id: string;
  title: string;
  description: string;
  roomId?: string;
  category: MaintenanceCategory;   // plumbing | electrical | hvac | ...
  priority: MaintenancePriority;   // emergency | high | medium | low
  status: MaintenanceStatus;
  reportedBy: string;
  assignedTo?: string;
  estimatedCost?: number;
  actualCost?: number;
  comments: Comment[];
  resolutionNotes?: string;
}

InventoryProduct

interface InventoryProduct {
  id: string;
  name: string;
  sku?: string;
  category: InventoryCategory;   // linens | toiletries | cleaning | ...
  unit: string;
  currentStock: number;
  minimumStock: number;
  reorderPoint: number;
  unitCost: number;
  supplier?: string;
  movements: StockMovement[];
}

interface StockMovement {
  id: string;
  type: 'in' | 'out' | 'adjustment';
  quantity: number;
  previousStock: number;
  newStock: number;
  performedBy: string;
}

Room

interface Room {
  id: string;
  name: string;
  number: string;
  floor: number;
  type: RoomType;       // single | double | twin | suite | ...
  capacity: number;
  basePrice: number;
  amenities: string[];
  status: RoomStatus;
}

API Reference

Riferimento completo dei metodi esposti dall'hook usePMS.

State Properties

PropertyTipoDescrizione
loadingbooleanTrue durante il caricamento iniziale
initializedbooleanTrue quando il PMS è inizializzato
reservationsReservation[]Lista prenotazioni
housekeepingTasksHousekeepingTask[]Lista task pulizie
roomStatusesRecord<string, RoomStatus>Mappa stato camere
maintenanceTicketsMaintenanceTicket[]Lista ticket manutenzione
inventoryInventoryProduct[]Lista prodotti inventario
roomsRoom[]Lista camere

Reservation Methods

MetodoParametriDescrizione
addReservationdata: Partial<Reservation>Crea nuova prenotazione
updateReservationid, updatesAggiorna prenotazione
deleteReservationid: stringElimina prenotazione
checkInid, data?Esegue check-in
checkOutid, data?Esegue check-out
getArrivalsdate: DateArrivi del giorno
getDeparturesdate: DatePartenze del giorno

Housekeeping Methods

MetodoParametriDescrizione
addHousekeepingTaskdataCrea task pulizia
completeHousekeepingTaskid, data?Completa task
updateRoomStatusroomId, statusAggiorna stato camera

Struttura API REST Suggerita

// Reservations
GET    /api/pms/reservations
POST   /api/pms/reservations
GET    /api/pms/reservations/:id
PUT    /api/pms/reservations/:id
DELETE /api/pms/reservations/:id
POST   /api/pms/reservations/:id/checkin
POST   /api/pms/reservations/:id/checkout

// Housekeeping
GET    /api/pms/housekeeping/tasks
POST   /api/pms/housekeeping/tasks
PUT    /api/pms/housekeeping/tasks/:id
POST   /api/pms/housekeeping/tasks/:id/complete

// Maintenance
GET    /api/pms/maintenance/tickets
POST   /api/pms/maintenance/tickets
PUT    /api/pms/maintenance/tickets/:id
POST   /api/pms/maintenance/tickets/:id/comments

// Inventory
GET    /api/pms/inventory/products
POST   /api/pms/inventory/products
PUT    /api/pms/inventory/products/:id
POST   /api/pms/inventory/products/:id/stock

State Management

Il PMS utilizza un pattern Flux-like con React Context + Custom Hooks per la gestione dello stato.

Flusso degli Aggiornamenti

1. User Action (es. click "Completa Task")
       ↓
2. Component chiama metodo hook (completeHousekeepingTask)
       ↓
3. Hook aggiorna stato locale (setHousekeepingTasks)
       ↓
4. Hook chiama servizio (pmsService.housekeeping.complete)
       ↓
5. Servizio aggiorna dati interni
       ↓
6. Hook triggera salvataggio (saveToStorage)
       ↓
7. React re-renderizza componenti interessati

Persistenza Automatica

// Ogni cambio di stato triggera il salvataggio automatico
useEffect(() => {
  if (initialized) {
    const dataToSave = {
      version: PMS_VERSION,
      propertyId: currentPropertyId,
      reservations, housekeepingTasks, roomStatuses,
      maintenanceTickets, inventory, staffTasks, rooms,
      savedAt: new Date().toISOString()
    };
    localStorage.setItem(PMS_STORAGE_KEY, JSON.stringify(dataToSave));
  }
}, [initialized, reservations, housekeepingTasks, maintenanceTickets, inventory]);

Separazione Multi-Property

I dati sono filtrati per propertyId per supportare la gestione multi-proprietà:

const getPropertyReservations = useCallback(() => {
  return reservations.filter(r => r.propertyId === currentPropertyId);
}, [reservations, currentPropertyId]);

Migrazione a Backend Reale

// Prima (localStorage - demo)
const loadData = () => {
  const saved = localStorage.getItem(PMS_STORAGE_KEY);
  return saved ? JSON.parse(saved) : null;
};

// Dopo (API REST - produzione)
const loadData = async () => {
  const response = await fetch('/api/pms/data');
  return response.json();
};

Performance e Ottimizzazione

Strategie implementate per mantenere il PMS reattivo e fluido anche con grandi quantità di dati.

Memoizzazione

// Memoizza calcoli costosi
const occupancyRate = useMemo(() => {
  const occupied = reservations.filter(r =>
    r.status === RESERVATION_STATUS.CHECKED_IN
  ).length;
  return (occupied / rooms.length) * 100;
}, [reservations, rooms.length]);

// Memoizza callback passati come props
const handleClick = useCallback((id) => {
  setSelectedReservation(id);
}, []);

Virtualizzazione Liste

Per liste con oltre 100 elementi, viene utilizzata la virtualizzazione con react-window:

import { FixedSizeList } from 'react-window';

<FixedSizeList height={600} itemCount={reservations.length} itemSize={80}>
  {({ index, style }) => (
    <ReservationRow reservation={reservations[index]} style={style} />
  )}
</FixedSizeList>

Lazy Loading delle Pagine

const PMSDashboardPage = lazy(() => import('./pages/PMSDashboardPage'));
const CalendarPage = lazy(() => import('./pages/ReservationsCalendarPage'));

<Suspense fallback={<LoadingSpinner />}>
  <Routes>...</Routes>
</Suspense>

Debouncing

import { useDebouncedCallback } from 'use-debounce';

const debouncedSearch = useDebouncedCallback((query) => {
  setSearchResults(filterReservations(query));
}, 300);

// Salvataggio localStorage differito (max 1 volta/secondo)
const saveToStorage = useDebouncedCallback(() => {
  localStorage.setItem(PMS_STORAGE_KEY, JSON.stringify(state));
}, 1000);

Metriche Target

MetricaTargetAzione se superato
First Paint< 1.5sOttimizzare bundle
Time to Interactive< 3sLazy loading
Largest Contentful Paint< 2.5sOttimizzare immagini
Re-renders per interazione< 3Memoizzazione

Sicurezza

La sicurezza nel PMS segue il principio della Defense in Depth: layer multipli di protezione.

Validazione Input

const validateReservation = (data) => {
  const errors = [];

  // Nome ospite: richiesto, no HTML
  if (!data.guestName || data.guestName.trim() === '')
    errors.push('Nome ospite richiesto');
  if (/<[^>]*>/.test(data.guestName))
    errors.push('Nome non valido');

  // Date: check-in prima di check-out
  if (new Date(data.checkOut) <= new Date(data.checkIn))
    errors.push('Check-out deve essere dopo check-in');

  // Email: formato valido se presente
  if (data.guestEmail && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.guestEmail))
    errors.push('Email non valida');

  return { valid: errors.length === 0, errors };
};

Sanitizzazione Output

import DOMPurify from 'dompurify';

const SafeText = ({ text }) => {
  const clean = DOMPurify.sanitize(text, {
    ALLOWED_TAGS: [], ALLOWED_ATTR: []
  });
  return <span>{clean}</span>;
};

Autorizzazione Basata su Ruoli

const ROLES = { ADMIN: 'admin', MANAGER: 'manager',
  RECEPTIONIST: 'receptionist', HOUSEKEEPER: 'housekeeper' };

const PERMISSIONS = {
  [ROLES.ADMIN]: ['*'],
  [ROLES.MANAGER]: ['reservations.*', 'housekeeping.*', 'maintenance.*'],
  [ROLES.RECEPTIONIST]: ['reservations.*', 'housekeeping.read'],
  [ROLES.HOUSEKEEPER]: ['housekeeping.own', 'maintenance.create']
};

const hasPermission = (user, permission) => {
  const perms = PERMISSIONS[user.role] || [];
  return perms.includes('*') || perms.includes(permission);
};

Protezione Dati Sensibili

Attenzione: Non salvare mai in localStorage numeri di documenti completi, password, token di accesso, numeri di carte di credito o dati biometrici. Salvare solo riferimenti parziali (es. ultime 4 cifre del documento).

Audit Trail

const auditLog = (action, details) => {
  const entry = {
    timestamp: new Date().toISOString(),
    userId: currentUser.id,
    action,
    details
  };
  // Demo: localStorage / Produzione: API server
  const logs = JSON.parse(localStorage.getItem('pms_audit_log') || '[]');
  logs.push(entry);
  localStorage.setItem('pms_audit_log', JSON.stringify(logs.slice(-1000)));
};

Troubleshooting

Problemi comuni e soluzioni per lo sviluppo e il debug del PMS.

Il PMS non carica i dati

Causa: localStorage corrotto o versione incompatibile.

Soluzione:

// In console browser
localStorage.removeItem('checkin_pms_data');
// Ricarica la pagina

Prenotazioni non visibili nel calendario

Causa: Il propertyId delle prenotazioni non corrisponde a currentPropertyId.

Soluzione: Verificare che i filtri per proprietà siano allineati nel DataContext.

Drag & Drop non funziona

Causa: Browser non supporta HTML5 Drag and Drop.

Soluzione: Utilizzare un browser moderno (Chrome 90+, Firefox 88+, Safari 14+, Edge 90+) oppure implementare un fallback touch.

Abilitare Debug Mode

// In pmsService.js
const DEBUG = true;
const log = (...args) => {
  if (DEBUG) console.log('[PMS]', ...args);
};

Reset Completo del PMS

Per ripristinare il PMS allo stato iniziale con dati demo freschi:

// In console browser
localStorage.removeItem('checkin_pms_data');
localStorage.removeItem('checkin_pms_settings');
window.location.reload();

Suggerimento: Per segnalare bug o richiedere nuove funzionalità, contattaci via WhatsApp o email.

Pronto a iniziare lo sviluppo?

Clona il repository, avvia il dev server e inizia a contribuire al PMS di CheckIn Facile.

Codice Sorgente Demo Live