Manuale Operativo - Calendar Engine, Mobile e WebTop¶
Scopo¶
Questo manuale definisce come usare e rilasciare il nuovo motore calendario esterno in modo progressivo.
L'obiettivo operativo e avere un calendario unico consultabile da:
- SafeOps;
- WebTop su NethServer 8;
- smartphone e tablet Android;
- iPhone e iPad;
- Outlook, Google Calendar e Apple Calendar tramite feed standard.
Regola Base¶
Il calendario mostra la pianificazione. La sorgente operativa resta il gestionale che ha creato il lavoro.
Esempi:
- un ticket resta governato dal modulo Ticket;
- un RAS resta governato dal workflow RAS;
- un evento personale resta governato dal calendario utente;
- il motore calendario normalizza, pubblica e sincronizza.
Fasi Operative¶
Fase 0 - Preparazione¶
Prima di attivare il motore:
- scegliere un tenant pilota;
- scegliere 2 o 3 utenti pilota;
- verificare che ogni utente abbia email e ruolo corretti;
- verificare timezone tenant, preferibilmente
Europe/Rome; - confermare l'host del motore calendario;
- preparare token interni tra SafeOps e motore.
Checklist:
- [ ] tenant pilota definito;
- [ ] utenti pilota definiti;
- [ ] host motore definito;
- [ ] backup DB SafeOps recente;
- [ ] accesso WebTop disponibile;
- [ ] DNS e certificato HTTPS pronti.
Configurazione SafeOps per tenant pilota:
CALENDAR_ENGINE_ENABLED=true
CALENDAR_ENGINE_BASE_URL=http://127.0.0.1:18092
CALENDAR_ENGINE_PUBLIC_BASE_URL=https://safeops.nxt-sense.eu/calendar-engine
CALENDAR_ENGINE_WEBTOP_BASE_URL=http://10.50.0.200:18080/calendar-engine
CALENDAR_ENGINE_SECRET=<segreto-condiviso-minimo-32-caratteri>
CALENDAR_ENGINE_TIMEOUT_SECONDS=8
CALENDAR_ENGINE_SCHEDULED_SYNC_ENABLED=true
CALENDAR_ENGINE_SCHEDULED_SYNC_MINUTE=17
CALENDAR_ENGINE_SCHEDULED_SYNC_HOUR=*
CALENDAR_ENGINE_SCHEDULED_SYNC_SOURCES=all
CALENDAR_ENGINE_SCHEDULED_SYNC_LIMIT=500
CALENDAR_ENGINE_SCHEDULED_SYNC_BATCH_SIZE=100
Configurazione motore:
CALENDAR_ENGINE_SECRET=<stesso-segreto>
CALENDAR_ENGINE_DB_PATH=/var/lib/safeops-calendar/calendar_engine.sqlite3
CALENDAR_ENGINE_DEFAULT_TZ=Europe/Rome
CALENDAR_ENGINE_PORT=18092
CALENDAR_ENGINE_FEED_PAST_DAYS=365
CALENDAR_ENGINE_FEED_FUTURE_DAYS=180
CALENDAR_ENGINE_FEED_MAX_EVENTS=5000
Controllo servizio:
curl http://127.0.0.1:18092/healthz
curl https://safeops.nxt-sense.eu/calendar-engine/healthz
Pagina admin SafeOps:
Configurazioni -> Calendar Engine
La pagina consente a un platform admin di modificare:
- abilitazione motore;
- URL interno API;
- URL pubblico feed WebCal/ICS;
- timeout chiamate;
- giorni storico/futuro esposti nei feed;
- limite massimo eventi per feed;
- creazione feed tenant/utente;
- revoca feed esistenti;
- diagnostica runtime del motore;
- stato sync automatico, tenant sincronizzati, fonti e limiti.
Il segreto HMAC non e modificabile dalla pagina admin e deve restare gestito da .env/deploy.
I parametri feed richiedono il riavvio di safeops-calendar-engine.service.
Il token feed completo viene mostrato solo al momento della creazione: copiarlo subito in WebTop o nel calendario mobile.
Unità systemd preparata:
deploy/systemd/safeops-calendar-engine.service
Installazione operativa, da eseguire solo al momento del deploy:
install -d /home/safeops/data/calendar_engine
cp deploy/systemd/safeops-calendar-engine.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now safeops-calendar-engine.service
systemctl status safeops-calendar-engine.service
Nota esposizione rete:
- l'unita fornita ascolta su
127.0.0.1:18092; - per WebTop esterno usare reverse proxy HTTPS verso
127.0.0.1:18092; - aprire direttamente
0.0.0.0:18092solo in rete interna controllata e con firewall esplicito.
Path pubblico consigliato:
/calendar-engine/
Esempio health via reverse proxy:
curl https://safeops.nxt-sense.eu/calendar-engine/healthz
Fase 1 - Feed ICS Read-Only¶
Questa e la prima fase da usare in produzione.
Il motore espone un feed ICS per utente o per tenant. WebTop sottoscrive il feed come calendario Internet.
Stato implementativo attuale:
- gli appuntamenti RAS creati o aggiornati da SafeOps vengono pubblicati verso Calendar Engine quando il flag e attivo;
- ticket appointment ed eventi personali hanno adapter pronti e sono inclusi nel sync schedulato;
- il backfill manuale puo pubblicare ticket, eventi personali e RAS esistenti tramite CLI;
- lo sync automatico Celery pubblica periodicamente ticket, eventi personali e RAS per i tenant con modulo calendario abilitato;
- ogni utente attivo abilitato al modulo calendario puo vedere in SafeOps il link WebTop personale;
- il feed ICS del motore resta read-only.
Sync automatico in produzione:
- task Celery:
app.tasks.calendar_engine_scheduled_sync; - schedule predefinita: ogni ora al minuto
17; - tenant: derivati da
user_role_profile_assignmentattivi e filtrati da modulocalendar; - fonti:
all, cioe personali, RAS e ticket; - limite predefinito: 500 record per sorgente/tenant;
- batch predefinito: 100 eventi per chiamata al motore.
Primo sync reale o riallineamento manuale:
python -c "from dotenv import load_dotenv; load_dotenv('.env'); from app import app; from app.services.calendar_engine_sync import run_calendar_engine_scheduled_sync; ctx=app.app_context(); ctx.push(); print(run_calendar_engine_scheduled_sync(sources='all', limit=500, batch_size=100, dry_run=False)); ctx.pop()"
Backfill iniziale in dry-run:
flask --app app calendar_engine_sync --tenant-key tenant_demo --source all --limit 100
Backfill effettivo:
flask --app app calendar_engine_sync --tenant-key tenant_demo --source all --limit 100 --apply
Sorgenti disponibili:
ticketpersonalrasall
Per il primo collaudo usare sempre --source ras e --limit 20, verificare il JSON prodotto, poi ripetere con --apply.
Flusso:
SafeOps -> Calendar Engine -> feed ICS -> WebTop -> smartphone/tablet
Procedura:
- aprire
Calendario Globalein SafeOps con un utente abilitato al modulo calendario; - copiare il link WebTop personale mostrato nella pagina;
- aprire WebTop;
- creare un calendario Internet di tipo WebCal/ICS;
- incollare l'URL del feed;
- impostare sincronizzazione automatica;
- verificare gli eventi su WebTop;
- verificare la comparsa su telefono/tablet.
Per admin o casi speciali si puo ancora generare un token feed dalla pagina /admin/calendar-engine/ o via CLI.
Creazione token feed tramite API interna firmata:
POST /api/v1/feed-tokens
Payload minimo:
{
"tenant_key": "tenant_demo",
"scope": "user",
"user_id": 7,
"label": "SafeOps - Mario Rossi",
"sources": ["ticket_appointment", "ras_appointment", "user_calendar_event"]
}
Creazione token tramite CLI SafeOps:
flask --app app calendar_engine_feed_create \
--tenant-key tenant_demo \
--scope user \
--user-id 7 \
--label "SafeOps - Mario Rossi" \
--source ras_appointment \
--source ticket_appointment \
--source user_calendar_event
La risposta contiene:
feed_url: URL interno generato dal motore;public_feed_url: URL pubblico pronto per WebTop/mobile, seCALENDAR_ENGINE_PUBLIC_BASE_URLe configurato.
Usare public_feed_url in WebTop come calendario Internet WebCal/ICS.
Revoca token:
flask --app app calendar_engine_feed_revoke --token <token-originale>
Controlli:
- l'utente vede solo il proprio perimetro;
- gli eventi privati non appaiono a utenti non proprietari;
- gli eventi RAS non sono duplicati;
- gli orari sono corretti su mobile;
- evento cancellato o annullato non resta attivo.
Fase 2 - Calendario Globale SafeOps via Motore¶
Solo dopo Fase 1 stabile.
Procedura:
- abilitare flag per tenant pilota;
- aprire Calendario Globale in SafeOps;
- confrontare eventi con calendario legacy;
- verificare filtri per sorgente;
- verificare filtri per utente;
- mantenere fallback al calendario legacy.
Rollback:
- disabilitare flag motore;
- riaprire Calendario Globale;
- verificare che SafeOps legga di nuovo dalle tabelle locali.
Fase 3 - Scrittura Controllata¶
Da attivare solo dopo collaudo.
Operazioni abilitate:
- nuovo appuntamento personale;
- spostamento appuntamento personale;
- aggiornamento appuntamento personale;
- eventuale ripianificazione RAS tramite adapter SafeOps.
Regole:
- ogni modifica deve avere audit;
- ogni modifica deve verificare membership tenant;
- le modifiche da WebTop restano disabilitate finche non viene attivato CalDAV bidirezionale.
Fase 4 - CalDAV¶
CalDAV serve per sincronizzazione piu efficiente rispetto al feed ICS.
Da usare quando:
- i feed ICS diventano troppo pesanti;
- serve sync differenziale;
- serve preparare modifiche bidirezionali controllate.
Procedura:
- creare endpoint CalDAV del motore;
- configurare WebTop come calendario remoto CalDAV;
- verificare sync incrementale;
- confrontare eventi con feed ICS;
- dismettere feed ICS solo quando CalDAV e stabile.
Fase 5 - Bidirezionale WebTop¶
Non attivare in automatico.
Prima servono:
- matrice permessi;
- regole di conflitto;
- mapping completo source -> gestionale;
- audit visibile;
- test su tenant pilota.
Regole minime:
- un evento RAS modificato da WebTop deve aggiornare SafeOps solo se l'utente puo gestire quel RAS;
- un ticket appointment modificato da WebTop deve aggiornare il ticket relativo;
- eventi completati o firmati non devono essere spostati senza ruolo admin;
- ogni conflitto deve essere bloccato o marcato come
needs_review.
Integrazione WebTop NethServer 8¶
WebTop su NethServer 8 supporta:
- ActiveSync;
- CalDAV;
- CardDAV;
- calendari remoti WebCal/ICS.
Per Release 1 usare WebCal/ICS.
Configurazione WebTop¶
- Accedere a WebTop con l'utente interessato.
- Aprire Calendario.
- Clic destro su calendari personali.
- Selezionare aggiunta calendario Internet.
- Scegliere WebCal/ICS.
- Inserire URL feed generato dal motore.
- Salvare.
- Impostare sincronizzazione automatica ogni 15, 30 o 60 minuti.
Configurazione Mobile¶
Opzione consigliata:
- sincronizzare il dispositivo con WebTop via ActiveSync;
- abilitare il calendario remoto nel profilo WebTop;
- verificare colore, nome calendario e orari.
Opzione alternativa:
- iscrivere direttamente il telefono al feed ICS;
- usare questa opzione solo per utenti pilota o calendari read-only.
Naming Feed¶
Usare nomi chiari.
Esempi:
SafeOps - Mario RossiSafeOps - Tecnici tenant_safecondoSafeOps - RAS tenant_besantSafeOps - Multi Tenant Direzione
Sicurezza Operativa¶
Regole obbligatorie:
- non inviare URL feed in chat pubbliche;
- revocare il token se un dispositivo viene perso;
- non creare feed tenant per utenti non admin;
- non usare un feed multi-tenant senza motivazione operativa;
- non usare token permanenti per test.
Rotazione:
- token utente: rinnovo consigliato ogni 180 giorni;
- token tenant/admin: rinnovo consigliato ogni 90 giorni;
- token test: scadenza massima 7 giorni.
Troubleshooting¶
Health motore¶
Controllare prima questi endpoint:
curl http://127.0.0.1:18092/healthz
curl http://127.0.0.1:18080/calendar-engine/healthz
curl https://safeops.nxt-sense.eu/calendar-engine/healthz
Risposta attesa:
{"ok": true, "service": "calendar-engine"}
Se HTTPS funziona ma locale no, verificare porta e systemd.
Se locale funziona ma HTTPS no, verificare reverse proxy NethSecurity sul path /calendar-engine.
Sync automatico fermo¶
Controllare:
systemctl is-active safeops-celery.service
systemctl is-active safeops-celery-beat.service
Poi aprire:
/admin/calendar-engine/
La sezione Sync automatico deve mostrare:
- stato
Attivo; - tenant sincronizzati non vuoti;
- fonti
all; - limiti coerenti con
.env.
WebTop non mostra eventi¶
Controllare:
- URL feed corretto;
- token non scaduto o revocato;
- HTTPS valido;
- range eventi (
CALENDAR_ENGINE_FEED_PAST_DAYSeCALENDAR_ENGINE_FEED_FUTURE_DAYS); - log accesso feed;
- timezone evento;
- sync automatico attivo;
- presenza eventi preparabili nella dry-run.
Eventi duplicati¶
Cause comuni:
- RAS esposto sia come
ras_appointmentsia cometicket_appointment; - stesso feed aggiunto due volte in WebTop;
- cambio source_id durante import.
Azione:
- verificare
source_system/source_type/source_id; - controllare deduplica RAS;
- rimuovere calendari duplicati da WebTop.
Orario errato¶
Controllare:
- timezone tenant;
- timezone WebTop;
- timezone dispositivo;
- conversione
starts_at_utc; - evento all-day trattato come evento orario.
Utente vede eventi non suoi¶
Bloccare subito:
- revocare il token feed;
- verificare membership tenant;
- controllare
visibility; - controllare
calendar_event_share; - aprire audit sicurezza.
Collaudo Minimo¶
Per ogni tenant pilota:
- creare un appuntamento personale privato;
- creare un appuntamento personale team;
- creare un appuntamento condiviso con un solo utente;
- verificare un ticket appointment;
- verificare un RAS appointment;
- verificare una data corso formazione;
- esportare feed ICS utente;
- importare feed in WebTop;
- verificare su iPhone/iPad;
- verificare su Android;
- revocare token;
- confermare che il feed non risponde piu.
Rollback¶
Fase 1:
- revocare token feed;
- rimuovere calendario Internet da WebTop;
- lasciare SafeOps invariato.
Fase 2:
- disabilitare flag motore calendario;
- usare Calendario Globale legacy;
- lasciare motore in sola lettura per diagnostica.
Fase 3 o successive:
- bloccare scritture dal motore;
- mantenere read-only;
- riconciliare eventi con audit prima di riattivare.
Responsabilita¶
Operatore:
- verifica appuntamenti e segnala anomalie.
Admin tenant:
- gestisce feed tenant e utenti pilota;
- revoca token;
- pulisce dal motore i token gia revocati;
- controlla visibilita.
Tecnico:
- usa calendario su mobile;
- non modifica eventi da WebTop finche il bidirezionale non e abilitato.
Sviluppo:
- mantiene adapter;
- monitora import;
- gestisce conflitti e audit.
Stato Attuale¶
Stato al 2026-08-03:
- Calendar Engine attivo su
127.0.0.1:18092; - bridge SafeOps attivo su
/calendar-engine; - URL pubblico HTTPS attivo su
https://safeops.nxt-sense.eu/calendar-engine; - URL LAN WebTop validato su
http://10.50.0.200:18080/calendar-engine; - feed personali WebTop provisionati per gli utenti attivi dei tenant calendario;
- sync schedulato Celery attivo ogni ora al minuto
17; - sync reale ricorrente completato con 73 eventi pubblicati e 0 errori;
- pagina admin con ultima sync registrata, analisi dry-run e pulizia sicura dei feed revocati;
- feed ICS con metadati WebCal completi,
ETag,Last-Modifiede cache privata breve; - WebTop resta in modalita read-only tramite ICS/WebCal.
Operazioni Admin Aggiunte¶
La pagina /admin/calendar-engine/ mostra:
- ultima sync registrata con data, tenant, fonti, scansionati, preparati, pubblicati, scartati, batch ed errori;
- analisi dry-run manuale senza pubblicare eventi;
- feed attivi/revocati con filtri per stato, ambito e ricerca utente/anagrafica;
- azione
Pulisci revocati, che elimina definitivamente solo i token gia revocati nel motore esterno.
La pulizia non revoca feed attivi e non tocca link WebTop ancora funzionanti.