Cartella Clinica
  • Python 59.8%
  • HTML 40.2%
Find a file
2026-05-18 18:08:18 +02:00
data/documents/PT-000001/2026/patient MFA e BlackList 2026-05-18 16:22:37 +02:00
static/img Initial cartclin app setup 2026-03-30 23:00:40 +02:00
templates MFA e BlackList 2026-05-18 18:08:18 +02:00
tests MFA e BlackList 2026-05-18 17:47:00 +02:00
.gitignore Initial cartclin app setup 2026-03-30 23:00:40 +02:00
__init__.py MFA e BlackList 2026-05-18 16:44:37 +02:00
access_control.py MFA e BlackList 2026-05-18 16:44:37 +02:00
access_log.py MFA e BlackList 2026-05-18 16:44:37 +02:00
api_auth.py MFA e BlackList 2026-05-18 16:44:37 +02:00
api_v1.py MFA e BlackList 2026-05-18 17:47:00 +02:00
app.py MFA e BlackList 2026-05-18 17:47:00 +02:00
audit_log.py MFA e BlackList 2026-05-18 16:44:37 +02:00
auth_service.py MFA e BlackList 2026-05-18 16:44:37 +02:00
cartclin.db Modifica da IA sembra andare tutto. 2026-04-01 14:02:01 +02:00
CHANGELOG.md MFA e BlackList 2026-05-18 17:47:00 +02:00
clinical_events.py MFA e BlackList 2026-05-18 16:44:37 +02:00
clinical_exam_catalog.py MFA e BlackList 2026-05-18 16:44:37 +02:00
clinical_exam_labs.py MFA e BlackList 2026-05-18 16:44:37 +02:00
clinical_exams.py MFA e BlackList 2026-05-18 16:44:37 +02:00
db.py MFA e BlackList 2026-05-18 17:27:00 +02:00
db_backup.py MFA e BlackList 2026-05-18 16:44:37 +02:00
diary.py MFA e BlackList 2026-05-18 16:44:37 +02:00
document_store.py MFA e BlackList 2026-05-18 17:47:00 +02:00
documents.py MFA e BlackList 2026-05-18 16:44:37 +02:00
failed_login_log.py MFA e BlackList 2026-05-18 16:44:37 +02:00
fhir_api.py MFA e BlackList 2026-05-18 16:44:37 +02:00
fhir_mapping.py MFA e BlackList 2026-05-18 16:44:37 +02:00
glycemia.py MFA e BlackList 2026-05-18 16:44:37 +02:00
LICENSE MFA e BlackList 2026-05-16 20:03:36 +02:00
log_archive.py MFA e BlackList 2026-05-18 16:44:37 +02:00
login_security_policy.py MFA e BlackList 2026-05-18 16:44:37 +02:00
logoGazzinet.png Initial cartclin app setup 2026-03-30 23:00:40 +02:00
medication_administration.py MFA e BlackList 2026-05-18 16:44:37 +02:00
medications.py MFA e BlackList 2026-05-18 16:44:37 +02:00
models.py MFA e BlackList 2026-05-18 16:44:37 +02:00
NOTICE MFA e BlackList 2026-05-16 20:03:36 +02:00
nutrition.py MFA e BlackList 2026-05-18 16:44:37 +02:00
nutrition_api.py MFA e BlackList 2026-05-18 16:44:37 +02:00
patient_service.py MFA e BlackList 2026-05-18 17:27:00 +02:00
patients.py MFA e BlackList 2026-05-18 17:27:00 +02:00
pressure.py MFA e BlackList 2026-05-18 16:44:37 +02:00
ps_transfer.py MFA e BlackList 2026-05-18 17:47:00 +02:00
rate_limit.py MFA e BlackList 2026-05-18 16:44:37 +02:00
README.md MFA e BlackList 2026-05-18 18:08:18 +02:00
README_PRONTO_SOCCORSO.md MFA e BlackList 2026-05-18 17:47:00 +02:00
receipts.py MFA e BlackList 2026-05-18 16:44:37 +02:00
security.py MFA e BlackList 2026-05-18 16:44:37 +02:00
ui_labels.py MFA e BlackList 2026-05-18 18:08:18 +02:00
user_service.py MFA e BlackList 2026-05-18 16:44:37 +02:00
utils.py MFA e BlackList 2026-05-18 16:44:37 +02:00

CartClin

Documentazione tecnica dell'applicazione CartClin.

Versione documentata corrente: 1.1

Storico modifiche:

CartClin e' una web app Flask per la gestione di schede cliniche, pazienti, terapie, alimentazione assistita, diario, eventi sanitari, esami clinici, glicemia, pressione, documenti farmacia, invio in Pronto Soccorso e API protette JSON/FHIR.

Modulo Invio in Pronto Soccorso

La versione 1.1 aggiunge un modulo dedicato alla preparazione del trasferimento di un paziente verso il Pronto Soccorso. Il modulo include:

  • checklist sintetica stampabile A4
  • scheda accompagnamento paziente PS
  • export Markdown
  • collegamento documenti PDF via document store
  • campi paziente abituali utili al trasferimento
  • API REST CRUD /api/v1/patients/<id>/ps-transfers

Guida operativa breve: vedi README_PRONTO_SOCCORSO.md.

Questa documentazione descrive struttura, tabelle, sicurezza, permessi e aree funzionali. Non documenta come l'applicazione e' in esecuzione o come viene pubblicata.

Storia del programma / Program story

Italiano

Cartclin nasce prima di tutto da una storia personale. Non da un'idea commerciale, ma da un bisogno reale, vissuto ogni giorno accanto a una persona amata.

Quando mio padre, Amilcare Gozzi, si e ammalato gravemente, mi sono trovato ad affrontare una realta fatta di controlli continui, farmaci, crisi improvvise, valori da monitorare, pressioni, annotazioni e decisioni delicate da prendere rapidamente. Ogni giornata diventava una corsa contro il tempo, dove nulla poteva essere dimenticato.

Da tecnico informatico, ho sentito il bisogno di creare uno strumento che mi aiutasse a tenere traccia di tutto: eventi clinici, somministrazioni, variazioni dello stato di salute, parametri vitali e momenti critici. All'inizio era un programma semplice, nato esclusivamente per lui. Un modo per stargli vicino meglio. Un modo per prendermi cura di lui con piu attenzione, piu ordine e piu serenita.

Con il tempo, pero, quel progetto ha assunto un significato molto piu profondo.

Dopo la scomparsa di mio padre, ho deciso di non lasciare che quel lavoro restasse qualcosa di privato. Ho capito che la difficolta che avevo vissuto io era la stessa che affrontano ogni giorno famiglie, operatori sanitari e strutture che assistono persone anziane o fragili.

Cosi quel software, nato dal dolore ma anche dall'amore, e diventato Cartclin: un sistema pensato per aiutare chi si prende cura degli altri, semplificando la gestione quotidiana dell'assistenza e mettendo al centro la persona.

Perche' a volte le idee piu importanti non nascono in un ufficio. Nascono accanto a un letto, in silenzio, mentre si cerca semplicemente di fare il meglio possibile per qualcuno che si ama.

English

Cartclin was born first and foremost from a personal story. Not from a commercial idea, but from a real need, lived every day beside a loved one.

When my father, Amilcare Gozzi, became seriously ill, I found myself facing a reality made of constant checks, medications, sudden crises, values to monitor, blood pressure readings, notes, and delicate decisions to make quickly. Every day became a race against time, where nothing could be forgotten.

As an IT technician, I felt the need to create a tool that would help me keep track of everything: clinical events, administrations, changes in health status, vital parameters, and critical moments. At first it was a simple program, created exclusively for him. A way to stay closer to him. A way to take care of him with more attention, more order, and more peace of mind.

Over time, however, that project took on a much deeper meaning.

After my father's passing, I decided not to let that work remain something private. I realized that the difficulty I had experienced was the same one faced every day by families, healthcare workers, and facilities caring for elderly or fragile people.

So that software, born from pain but also from love, became Cartclin: a system designed to help those who care for others, simplifying the daily management of care and keeping the person at the center.

Because sometimes the most important ideas are not born in an office. They are born beside a bed, in silence, while simply trying to do the best possible for someone you love.

Licenza

CartClin e' distribuito sotto licenza Apache License 2.0.

File inclusi nel repository per la licenza:

In sintesi:

  • il software e' distribuito "AS IS"
  • e' consentito uso, modifica e ridistribuzione secondo i termini Apache 2.0
  • i file modificati dovrebbero mantenere le note richieste dalla licenza
  • il file NOTICE va mantenuto nelle distribuzioni dove richiesto

Note di rilascio repository

Nel rilascio del codice vanno considerati come dati/runtime locali e non come artefatti da pubblicare:

  • cartclin.db
  • eventuali farma_*.db legacy non piu' usati dal modello attuale
  • .flask_secret
  • contenuti di venv/
  • cache locali e __pycache__/

Il repository rilasciabile deve contenere il codice, i template, le risorse statiche, la documentazione e i file di licenza, ma non i database reali o i segreti d'ambiente.

Aree funzionali

  • autenticazione locale con sessione Flask
  • gestione utenti, ruoli e stato attivo
  • permessi per ruolo con bitmask READ, WRITE, EXEC
  • anagrafica pazienti
  • assegnazione pazienti a utenti non amministratori
  • terapie/farmaci per paziente
  • somministrazione farmaci giornaliera e opzionale con storico
  • alimentazione assistita con prescrizioni strutturate, vista cucina, vista reparto, alert e report
  • diario clinico
  • eventi sanitari
  • esami clinici e catalogo parametri
  • document store PDF unificato su filesystem con metadati nel DB principale
  • laboratori esami clinici
  • rilevazioni glicemia
  • rilevazioni pressione
  • scontrini/farmacia con PDF e report
  • esportazione dati paziente
  • invio email per export paziente e reset password
  • tema e lingua interfaccia per utente
  • API v1 con token Bearer
  • endpoint FHIR R4 in sola lettura per interoperabilita'
  • rate limit su endpoint sensibili
  • MFA via email configurabile per singolo utente
  • OTP/TOTP compatibile con Google Authenticator come fattore aggiuntivo
  • whitelist IP per singolo utente con blocco login web e API
  • blacklist IP per bloccare login da sorgenti non autorizzate
  • protezioni web CSRF e security headers
  • soft delete clinico con motivo obbligatorio e ripristino admin
  • audit log strutturato con storico e formato compatibile syslog
  • access log separato per web/API/FHIR
  • rilevazione tentativi di hacking su login, MFA/OTP, blacklist/whitelist IP e probing anonimo sospetto
  • limitazione dei body HTTP, dei CSV clinici e dei file di import backup per ridurre i rischi di resource exhaustion
  • storico dedicato dei tentativi di login falliti

Componenti principali

File Responsabilita'
app.py Entry point Flask, route globali, registrazione blueprint, sicurezza HTTP, configurazione, login e reset password
db.py Inizializzazione SQLite, tabelle principali, seed configurazioni e permessi admin
security.py Sessione utente, CSRF, decorator admin e permessi
auth_service.py Bitmask permessi e gestione autorizzazioni
user_service.py Utenti, password, reset token, preferenze utente
patient_service.py CRUD pazienti e assegnazioni utente-paziente
api_v1.py API JSON v1 con autenticazione Bearer
api_auth.py Creazione, validazione e revoca token API
fhir_api.py Endpoint FHIR R4
fhir_mapping.py Mapping tra dati CartClin e risorse FHIR
rate_limit.py Rate limit persistito su SQLite
audit_log.py Audit strutturato, query storico e messaggi syslog-like
access_log.py Storico accessi applicativi separato dall'audit
failed_login_log.py Storico dedicato dei login falliti
patients.py Blueprint pazienti, assegnazioni, export e invio email
medications.py Blueprint farmaci/terapie
medication_administration.py Blueprint somministrazione farmaci giornaliera e opzionale
nutrition.py Blueprint alimentazione assistita, prescrizioni, cucina, reparto, alert e report
nutrition_api.py API REST del modulo alimentazione assistita
diary.py Blueprint diario paziente
clinical_events.py Blueprint eventi sanitari
clinical_exams.py Blueprint esami clinici e import CSV
documents.py Blueprint documenti PDF paziente con filtri per modulo/record
document_store.py Storage filesystem PDF, metadati DB e validazioni upload
clinical_exam_catalog.py Catalogo parametri esami e range
clinical_exam_labs.py Laboratori selezionabili negli esami
glycemia.py Rilevazioni e report glicemia
pressure.py Rilevazioni e report pressione
receipts.py Scontrini farmacia su DB principale, PDF nel document store, export e report
ui_labels.py Label UI multilingua
utils.py Hash e verifica password
models.py Dataclass applicative

Database principale

Il database principale e' SQLite e viene inizializzato in modo idempotente da init_db().

Percorso applicativo:

cartclin.db

Tabelle rilevate:

api_tokens
app_config
assignments
authorizations
audit_logs
access_logs
allergens
failed_login_logs
clinical_events
clinical_exam_labs
clinical_exam_parameters
clinical_exam_reference_ranges
clinical_exams
diary
glicemie
integration_messages
medications
medication_administrations
meal_administrations
meal_deliveries
meal_rounds
nutrition_alerts
nutrition_meals
nutrition_prescription_history
nutrition_prescription_items
nutrition_prescriptions
patient_assignments
patient_identifiers
patients
pressioni
rate_limits
users

Nota: assignments e patient_assignments rappresentano entrambe il concetto di assegnazione paziente-utente. Nel codice corrente la tabella usata dai servizi applicativi e' assignments.

Tabelle

users

Contiene gli utenti applicativi locali.

Campo Note
id Primary key
username Univoco, normalizzato in minuscolo
password Hash PBKDF2 con salt
email Univoca, usata anche per reset password
role Ruolo applicativo, ad esempio admin o user
password_expiry Data scadenza password
active Abilita/disabilita login
reset_token Token reset password hashato
reset_expiry Scadenza reset password
theme Preferenza UI light/dark
patient_export_mail_template Template personale export paziente
ui_language Lingua interfaccia
mfa_email_enabled Abilitazione MFA email per singolo utente
mfa_email Email dedicata MFA; se vuota viene usata email
mfa_totp_enabled Abilitazione OTP/TOTP per singolo utente
mfa_totp_secret Secret TOTP persistito
mfa_totp_enrolled_at Timestamp prima registrazione OTP
login_ip_whitelist_enabled Abilita il vincolo IP per il singolo utente
login_ip_whitelist Lista multilinea di IP o CIDR autorizzati

authorizations

Permessi per ruolo e pagina.

Campo Note
id Primary key
role Ruolo applicativo
page Area funzionale
perm Bitmask intera 0..7

Bitmask:

Bit Costante Valore
lettura READ 4
scrittura WRITE 2
esecuzione EXEC 1
pieno accesso `READ WRITE

La coppia (role, page) e' univoca.

patients

Anagrafica pazienti.

Campo Note
id Primary key
nome Nome paziente
cognome Cognome paziente
codice_fiscale Univoco, normalizzato in maiuscolo
data_nascita Data di nascita
reparto Reparto/area assistenziale
camera Camera
letto Letto/postazione
attivo Paziente/ospite attivo
medico Medico di riferimento
contatto_medico Contatto medico
email_medico Email medico
audit_code Codice tecnico stabile per audit/log
note Note libere
medication_administration_enabled Abilita la somministrazione farmaci per il paziente
deleted_at Timestamp annullamento logico
deleted_by Utente che ha annullato
delete_reason Motivo annullamento

assignments

Associazione molti-a-molti tra pazienti e utenti.

Campo Note
patient_id FK logica verso patients.id
user_id FK logica verso users.id

Primary key composta: (patient_id, user_id).

Gli utenti non admin vedono solo i pazienti assegnati.

patient_assignments

Tabella alternativa per assegnazioni paziente-utente, con foreign key ON DELETE CASCADE.

Nel codice applicativo corrente i servizi usano assignments; questa tabella va considerata legacy o parallela finche' non viene consolidata.

medications

Terapie/farmaci per paziente.

Campo Note
id Primary key
patient_id Paziente
nome_farmaco Nome farmaco
modalita_uso Note uso
prima_colazione Flag assunzione
dopo_colazione Flag assunzione
prima_pranzo Flag assunzione
dopo_pranzo Flag assunzione
prima_cena Flag assunzione
dopo_cena Flag assunzione
prima_dormire Flag assunzione
libero Flag uso libero
deleted_at Timestamp annullamento logico
deleted_by Utente che ha annullato
delete_reason Motivo annullamento

diary

Diario clinico del paziente.

Campo Note
id Primary key
patient_id Paziente
date Data voce
diary_time Ora opzionale della voce
description Testo voce
deleted_at Timestamp annullamento logico
deleted_by Utente che ha annullato
delete_reason Motivo annullamento

medication_administrations

Registro delle somministrazioni farmaci standard e opzionali.

Campo Note
id Primary key
patient_id Paziente
medication_id Farmaco associato
scheduled_date Data prevista
scheduled_time Ora prevista
slot_key Fascia tecnica, ad esempio prima_colazione o optional
slot_label Etichetta della fascia
recorded_at Data/ora effettiva di registrazione
operator_user_id Utente che registra
operator_username Username operatore
outcome somministrato o non_somministrato
note Nota opzionale o obbligatoria se non somministrato
status Stato registrazione
created_at Creazione record
updated_at Ultimo aggiornamento

Indice:

  • idx_medication_administrations_patient_date
  • idx_medication_administrations_unique_v2

allergens

Catalogo codificato di allergeni e intolleranze riusato dal modulo alimentazione assistita.

Campo Note
id Primary key
name Nome allergene
code Codice univoco

nutrition_prescriptions

Prescrizioni alimentari strutturate per paziente/ospite.

Campo Note
id Primary key
patient_id Paziente
feeding_status normale, assistita, digiuno_npo, enterale, parenterale
diet_type normale, liquida, semiliquida, frullata, omogeneizzata, morbida, altro
food_texture_level Livello consistenza cibo
liquid_texture_level Livello consistenza liquidi
dysphagia Flag disfagia
thickened_liquids Flag liquidi addensati
needs_assistance Flag necessita assistenza
assistance_type autonoma, sorveglianza, imboccamento, postura_assistita
clinical_notes Note sanitarie strutturate/libere
valid_from Data inizio validita'
valid_to Data fine validita'
prescribed_by Operatore prescrittore
validated_by Operatore validatore
status active, suspended, expired
created_at Creazione
updated_at Ultimo aggiornamento
deleted_at Timestamp annullamento logico
deleted_by Utente che ha annullato
delete_reason Motivo annullamento

Indice: idx_nutrition_prescriptions_patient_dates.

nutrition_prescription_items

Elementi codificati associati alla prescrizione alimentare.

Campo Note
id Primary key
prescription_id Prescrizione collegata
allergen_id Allergene/intolleranza codificato
item_type allergen oppure intolerance
severity Severita' clinica
notes Note aggiuntive

Indice: idx_nutrition_prescription_items_prescription.

nutrition_prescription_history

Storico completo delle modifiche alle prescrizioni alimentari.

Campo Note
id Primary key
prescription_id Prescrizione collegata
patient_id Paziente
action create o update
old_value JSON precedente
new_value JSON aggiornato
changed_by Operatore che ha modificato
created_at Data/ora modifica

nutrition_meals

Anagrafica tecnica dei pasti selezionabili dal modulo, distinta dalla pianificazione menu.

Campo Note
id Primary key
name Nome pasto/preparazione
meal_type breakfast, lunch, dinner, snack
diet_type Tipo dieta compatibile
food_texture_level Consistenza cibo
liquid_texture_level Consistenza liquidi
included_allergen_codes JSON con codici allergeni inclusi
active Disponibilita' del pasto

meal_rounds

Turni pasto giornalieri pianificati.

Campo Note
id Primary key
round_date Data turno
meal_type breakfast, lunch, dinner, snack
status Stato round
created_at Creazione

Vincolo univoco: (round_date, meal_type).

meal_deliveries

Pianificazione e consegna del pasto per singolo paziente e turno.

Campo Note
id Primary key
meal_round_id Turno pasto
patient_id Paziente
prescription_id Prescrizione usata
meal_id Pasto/prodotto selezionato
delivery_status planned, blocked, prepared, delivered, not_delivered, cancelled
delivered_by Operatore consegna
delivered_at Data/ora consegna
anomaly_notes Anomalie consegna
blocked_reason Motivo blocco NPO/conflitto
created_at Creazione
updated_at Ultimo aggiornamento

Indice: idx_meal_deliveries_round_status.

meal_administrations

Registrazione del consumo e della somministrazione al paziente.

Campo Note
id Primary key
meal_delivery_id Consegna collegata, univoca
administered_by Operatore che registra
administered_at Data/ora registrazione
consumed_percentage 0, 25, 50, 75, 100
refused Rifiuto del pasto
fluids_ml Liquidi assunti in ml
problems JSON con problemi rilevati
notes Note clinico-operative
created_at Creazione
updated_at Ultimo aggiornamento

nutrition_alerts

Alert e non conformita' del modulo alimentazione assistita.

Campo Note
id Primary key
patient_id Paziente
meal_delivery_id Consegna correlata, se presente
alert_type npo_block, missing_prescription, blocked_delivery, allergen_conflict, meal_refused, low_fluids, swallowing_risk, consecutive_no_intake
severity high, medium, low
message Messaggio operativo
status open, resolved
created_at Apertura alert
resolved_at Chiusura
resolved_by Operatore che chiude

Indice: idx_nutrition_alerts_status_created.

clinical_events

Eventi sanitari del paziente.

Campo Note
id Primary key
patient_id Paziente
event_date Data evento
event_type Tipo evento
facility Struttura
symptoms Sintomi
diagnosis_summary Sintesi diagnosi
outcome Esito
therapy Terapia indicata
doctor Medico
priority Priorita', default media
linked_event_id Evento collegato
notes Note
deleted_at Timestamp annullamento logico
deleted_by Utente che ha annullato
delete_reason Motivo annullamento

Indice: idx_clinical_events_patient_date.

clinical_exams

Esami clinici del paziente.

Campo Note
id Primary key
patient_id Paziente
exam_date Data esame
parameter_code Codice parametro da catalogo
parameter_name Nome parametro
parameter_value Valore rilevato
unit Unita' di misura
reference_range Range testuale
status Stato interpretativo
category Categoria
laboratory Laboratorio
clinical_relevance Rilevanza clinica
document_ref Riferimento documento
notes Note
deleted_at Timestamp annullamento logico
deleted_by Utente che ha annullato
delete_reason Motivo annullamento

Indici:

  • idx_clinical_exams_patient_date
  • idx_clinical_exams_parameter

clinical_exam_parameters

Catalogo parametri esami clinici.

Campo Note
id Primary key
code Codice univoco
name_it Nome italiano
name_en Nome inglese
category Categoria
default_unit Unita' predefinita
aliases Alias JSON testuale
enabled Abilitazione parametro

Indice: idx_clinical_exam_parameters_name_it.

clinical_exam_reference_ranges

Range e label interpretative per parametro.

Campo Note
id Primary key
parameter_id FK verso catalogo parametri, univoca
low_value Soglia bassa numerica
high_value Soglia alta numerica
reference_text Range testuale
low_label_it Label italiana valore basso
normal_label_it Label italiana valore normale
high_label_it Label italiana valore alto
low_label_en Label inglese valore basso
normal_label_en Label inglese valore normale
high_label_en Label inglese valore alto
enabled Abilitazione range
notes Note

Indice: idx_clinical_exam_reference_parameter.

clinical_exam_labs

Laboratori selezionabili negli esami clinici.

Campo Note
id Primary key
code Codice univoco
name Nome laboratorio
enabled Abilitazione

Indice: idx_clinical_exam_labs_name.

glicemie

Rilevazioni glicemia.

Campo Note
id Primary key
patient_id Paziente
date Data rilevazione
prima_colazione Valore
dopo_colazione Valore
prima_pranzo Valore
dopo_pranzo Valore
prima_cena Valore
dopo_cena Valore
prima_dormire Valore
deleted_at Timestamp annullamento logico
deleted_by Utente che ha annullato
delete_reason Motivo annullamento

pressioni

Rilevazioni pressione e battiti.

Campo Note
id Primary key
patient_id Paziente
date Data rilevazione
*_massima Pressione sistolica per fascia oraria
*_minima Pressione diastolica per fascia oraria
*_battiti Battiti per fascia oraria
deleted_at Timestamp annullamento logico
deleted_by Utente che ha annullato
delete_reason Motivo annullamento

Fasce gestite:

  • prima_colazione
  • dopo_colazione
  • prima_pranzo
  • dopo_pranzo
  • prima_cena
  • dopo_cena
  • prima_dormire

app_config

Configurazione applicativa persistita.

Campo Note
id Primary key
section Area configurazione
key Chiave
value Valore
description Descrizione
value_type string, integer, boolean, secret, text
updated_at Timestamp aggiornamento

Sezioni seed:

  • mail
  • patient_export_mail
  • ui_labels_meta
  • ui_labels

I valori secret sono mascherati in UI e possono essere gestiti anche tramite store separato.

api_tokens

Token API persistiti solo come hash.

Campo Note
id Primary key
user_id Utente proprietario
token_name Nome descrittivo
token_hash SHA-256 del token
created_at Creazione
last_used_at Ultimo uso
expires_at Scadenza
active Token attivo/revocato

Il token in chiaro viene restituito solo alla creazione.

patient_identifiers

Identificativi aggiuntivi per interoperabilita' esterna.

Campo Note
id Primary key
patient_id Paziente collegato
identifier_system Sistema identificativo, ad esempio URI locale/FHIR
identifier_value Valore identificativo
identifier_type Tipo descrittivo
assigning_authority Autorita' emittente
active Identificativo attivo

integration_messages

Inbox/outbox tecnica per integrazioni future HL7/FHIR.

Campo Note
id Primary key
direction inbound / outbound
standard Standard, ad esempio FHIR o HL7v2
message_type Tipo messaggio o risorsa
external_message_id ID esterno sorgente/destinatario
patient_id Paziente correlato, se noto
payload_raw Payload originale
payload_normalized Payload normalizzato
status Stato tecnico del messaggio
error_text Errore di lavorazione
created_at Ricezione o generazione
processed_at Lavorazione completata

rate_limits

Rate limit persistito per endpoint sensibili.

Campo Note
id Primary key
scope Ambito, per esempio web_login o api_auth_token
actor Identificativo chiamante, di solito IP
created_at Timestamp Unix

Indice: idx_rate_limits_scope_actor_created.

scontrini

La gestione scontrini usa il database principale per i metadati strutturati e il document store PDF su filesystem per il file allegato.

Campo Note
patient_id Paziente proprietario
id Primary key
data Data scontrino
note Note
importo Importo
document_id Collegamento al PDF nel document store
nome_file Nome file originale/sicuro
data_insert Timestamp inserimento
deleted_at Timestamp annullamento logico
deleted_by Utente che ha annullato
delete_reason Motivo annullamento

Limite upload PDF:

30 MB

La ricerca scontrini lavora sulla tabella unica scontrini e filtra per paziente, anno, note, date e importo.

Le stampe applicative devono mostrare solo il contenuto del report: elementi UI globali come il pulsante help flottante vengono esclusi via CSS di stampa.

Autenticazione web

L'autenticazione web e' locale, basata sulla tabella users.

Flusso:

  1. verifica che l'IP sorgente non sia in blacklist
  2. username normalizzato in minuscolo
  3. ricerca utente attivo
  4. verifica password PBKDF2
  5. se mfa_email_enabled=1, invio codice email e apertura challenge temporanea
  6. verifica codice MFA entro 5 minuti
  7. salvataggio uid nella sessione Flask
  8. applicazione preferenze tema e lingua

La password viene salvata come:

salt_hex:hash_hex

Algoritmo:

PBKDF2-HMAC-SHA256, 100000 iterazioni, salt casuale 16 byte

Reset password

Il reset password usa token monouso:

  • token random via secrets.token_urlsafe(32)
  • salvataggio hash sha256$... in users.reset_token
  • scadenza in users.reset_expiry
  • durata: 1 ora
  • cancellazione token dopo reset riuscito

Il reset e' protetto da rate limit.

MFA via email

La MFA e' configurabile per singolo utente dai form di creazione/modifica utente.

Campi:

  • mfa_email_enabled: richiede codice email al login
  • mfa_email: indirizzo dedicato per il codice MFA

Comportamento:

  • dopo username/password corretti, l'utente non viene ancora autenticato
  • CartClin genera un codice numerico a 6 cifre
  • il codice viene inviato via send_email()
  • in sessione viene conservato solo l'hash SHA-256 del codice
  • il codice scade dopo 5 minuti
  • al completamento corretto viene creata la sessione utente

Se mfa_email e' vuoto, viene usata l'email principale dell'utente. Se la MFA e' attiva ma non esiste alcuna email utilizzabile, il login viene bloccato con errore.

OTP/TOTP

CartClin supporta anche OTP/TOTP compatibile con Google Authenticator come fattore aggiuntivo rispetto alla MFA email.

Campi:

  • mfa_totp_enabled: abilita OTP/TOTP per l'utente
  • mfa_totp_secret: secret TOTP persistito
  • mfa_totp_enrolled_at: data/ora di prima registrazione

Comportamento:

  • se l'OTP e' abilitato ma non ancora registrato, al primo login viene mostrato il QR code
  • l'utente deve confermare un codice OTP valido per completare il primo accesso
  • dai login successivi il codice OTP viene richiesto dopo password e, se presente, dopo MFA email

Whitelist IP per utente

Ogni utente puo' avere una whitelist IP dedicata.

Campi:

  • login_ip_whitelist_enabled: attiva il controllo IP per l'utente
  • login_ip_whitelist: lista multilinea di IP o CIDR autorizzati

Regole:

  • una voce per riga
  • sono supportati IP singoli e reti CIDR
  • i commenti iniziano con #
  • se la whitelist e' attiva e nessuna riga valida combacia, il login viene bloccato
  • il controllo vale sia per il login web sia per POST /api/v1/auth/token

Blacklist IP login

La blacklist IP viene salvata in app_config, sezione security, chiave login_ip_blacklist.

Formato:

203.0.113.10
198.51.100.0/24
# commento opzionale

Regole:

  • una voce per riga
  • sono supportati IP singoli e reti CIDR
  • i commenti iniziano con #
  • il controllo usa l'IP sorgente calcolato da X-Forwarded-For, request.access_route o remote_addr
  • se l'IP combacia, POST /login e POST /api/v1/auth/token rispondono 403

Sessioni e CSRF

La sessione contiene:

Chiave Scopo
uid ID utente autenticato
_csrf_token Token CSRF web
theme Tema UI
ui_language Lingua UI

Protezioni:

  • cookie HttpOnly
  • cookie SameSite=Lax
  • cookie Secure quando la richiesta e' HTTPS o pubblicata come HTTPS
  • durata sessione permanente: 30 giorni se l'utente seleziona ricordami
  • CSRF obbligatorio sui POST web non API
  • confronto CSRF con hmac.compare_digest

Le API sotto /api/ non usano CSRF web; usano token Bearer.

Timeout sessione:

  • ogni utente puo' avere un timeout sessione dedicato
  • se il valore utente e' assente, viene usato il default globale session_default_hours
  • il default iniziale e' 9 ore
  • superato il tempo massimo di inattivita', l'utente viene disconnesso automaticamente

Security headers

CartClin imposta header HTTP difensivi:

  • Content-Security-Policy
  • Cross-Origin-Opener-Policy: same-origin
  • Cross-Origin-Resource-Policy: same-origin
  • Cache-Control: no-store

La CSP limita default, form, frame ancestors, immagini, font, script, stili e connessioni. Sono consentiti asset da cdn.jsdelivr.net dove necessario per l'interfaccia.

Permessi applicativi

I permessi sono basati su ruolo e pagina.

Pagine/aree principali:

  • dashboard
  • users
  • permissions
  • patients
  • patient_assignments
  • patient_export
  • patient_mail
  • mailsetting
  • medications
  • medication_administration
  • nutrition_prescriptions
  • nutrition_kitchen
  • nutrition_ward
  • nutrition_alerts
  • nutrition_reports
  • diary
  • clinical_events
  • clinical_exams
  • glycemia
  • pressure
  • receipts
  • settings
  • configuration

Gli admin ricevono permessi pieni sulle aree seed principali.

Decorator usati:

  • @admin_required
  • @require_perm(page, mask)
  • @api_require_perm(page, mask)

Controlli paziente:

  • gli admin accedono a tutti i pazienti
  • gli utenti non admin accedono solo ai pazienti presenti in assignments
  • le API applicano lo stesso vincolo su lettura e scrittura dei dati paziente

Soft delete clinico e ripristino

I record clinici e amministrativi sensibili non vengono piu' rimossi con DELETE FROM, ma annullati logicamente.

Moduli coperti:

  • pazienti
  • farmaci
  • diario
  • eventi sanitari
  • esami clinici
  • glicemia
  • pressione
  • scontrini farmacia

Meccanismo:

  • scrittura di deleted_at
  • scrittura di deleted_by
  • motivo obbligatorio in delete_reason
  • esclusione automatica dei record annullati da viste, report, export e API
  • pagina admin di ripristino: /configuration/deleted-records

Questo comportamento e' piu' coerente con tracciabilita', audit e contesto sanitario rispetto alla cancellazione fisica immediata.

API v1

Base logica:

/api/v1

Autenticazione:

Authorization: Bearer <token>

Endpoint principali:

Metodo Path Scopo
GET /api/v1/ Metadati API
POST /api/v1/auth/token Crea token Bearer
POST /api/v1/auth/revoke Revoca token corrente
GET /api/v1/me Profilo utente token
GET/POST /api/v1/patients Lista/creazione pazienti
GET/PUT/DELETE /api/v1/patients/<id> Dettaglio/modifica/eliminazione paziente
GET/PUT /api/v1/patients/<id>/assignments Assegnazioni paziente
GET/POST /api/v1/patients/<id>/medications Farmaci
PUT/DELETE /api/v1/patients/<id>/medications/<mid> Modifica/elimina farmaco
GET/POST /api/v1/patients/<id>/medication-administrations Somministrazioni farmaci
GET /api/v1/nutrition/allergens Catalogo allergeni
GET/POST /api/v1/nutrition/patients/<id>/prescriptions Prescrizioni alimentari
PUT /api/v1/nutrition/patients/<id>/prescriptions/<prescription_id> Modifica prescrizione alimentare
GET /api/v1/nutrition/kitchen Vista cucina alimentazione assistita
POST /api/v1/nutrition/deliveries/<delivery_id> Aggiorna consegna pasto
POST /api/v1/nutrition/administrations/<delivery_id> Registra consumo/somministrazione pasto
GET /api/v1/nutrition/alerts Lista alert nutrizione
POST /api/v1/nutrition/alerts/<alert_id>/resolve Risoluzione alert
GET /api/v1/nutrition/reports Report nutrizione
GET/POST /api/v1/patients/<id>/diary Diario
PUT/DELETE /api/v1/patients/<id>/diary/<did> Modifica/elimina diario
GET/POST /api/v1/patients/<id>/clinical-events Eventi sanitari
PUT/DELETE /api/v1/patients/<id>/clinical-events/<event_id> Modifica/elimina evento
GET/POST /api/v1/patients/<id>/clinical-exams Esami clinici
PUT/DELETE /api/v1/patients/<id>/clinical-exams/<exam_id> Modifica/elimina esame
GET/POST /api/v1/patients/<id>/documents Documenti PDF paziente
GET /api/v1/patients/<id>/documents/<document_id> Metadati documento
GET /api/v1/patients/<id>/documents/<document_id>/download Download documento
DELETE /api/v1/patients/<id>/documents/<document_id> Hide logico documento
GET/POST /api/v1/patients/<id>/glycemia Glicemia
PUT/DELETE /api/v1/patients/<id>/glycemia/<gid> Modifica/elimina glicemia
GET/POST /api/v1/patients/<id>/pressure Pressione
PUT/DELETE /api/v1/patients/<id>/pressure/<rid> Modifica/elimina pressione
GET/POST /api/v1/patients/<id>/receipts Scontrini
GET/PUT/DELETE /api/v1/patients/<id>/receipts/<year>/<receipt_id> Dettaglio/modifica/elimina scontrino
GET /api/v1/patients/<id>/export.txt Export testuale paziente
POST /api/v1/patients/<id>/export-email Invio export paziente via email

Le route DELETE dell'API non eliminano piu' fisicamente il record: applicano il soft delete logico dove previsto.

I token API:

  • sono creati dopo autenticazione username/password locale
  • sono generati con prefisso ctc_
  • sono salvati solo come SHA-256
  • hanno scadenza configurabile tra 1 e 365 giorni
  • aggiornano last_used_at a ogni uso valido
  • possono essere revocati impostando active = 0

FHIR R4

Base logica:

/fhir/R4

Autenticazione:

Authorization: Bearer <token>

Endpoint iniziali:

Metodo Path Scopo
GET /fhir/R4/metadata CapabilityStatement minimale
GET /fhir/R4/Patient Search Patient
GET /fhir/R4/Patient/<id> Read Patient
GET /fhir/R4/Observation Search Observation per paziente
GET /fhir/R4/Observation/<id> Read Observation

Mapping attuale:

  • patients -> Patient
  • clinical_exams -> Observation
  • glicemie -> Observation
  • pressioni -> Observation

Note:

  • il layer FHIR e' attualmente di sola lettura
  • riusa i permessi CartClin e le assegnazioni paziente-utente
  • le letture FHIR vengono registrate nell'audit con canale fhir
  • integration_messages e patient_identifiers sono la base dati per estensioni HL7/FHIR future

Rate limit

Endpoint protetti:

Scope Limite
web_login 10 tentativi ogni 600 secondi per IP
api_auth_token 10 tentativi ogni 600 secondi per IP
password_reset 5 tentativi ogni 1800 secondi per IP

Nel pannello Configuration esiste ora una sezione dedicata ai rate limit di autenticazione, separata dalle altre impostazioni di sicurezza, cosi il sistemista puo adattare piu facilmente i limiti a studi, RSA o ospedali dietro IP condiviso.

I record vecchi vengono rimossi durante il consumo del rate limit.

Audit e tracciabilita'

CartClin registra eventi strutturati in audit_logs per:

  • accessi amministrativi rilevanti
  • export/import database
  • import CSV esami clinici
  • create/update/delete/restore nei moduli principali
  • attivita' API JSON
  • letture FHIR

Caratteristiche:

  • pseudonimizzazione paziente tramite patients.audit_code
  • messaggio syslog_message compatibile con sistemi esterni
  • storico consultabile dalla UI admin
  • dettagli minimizzati per ridurre esposizione di dati sanitari nel log

In parallelo esistono anche:

  • access_logs: storico separato di accessi web, API e FHIR
  • failed_login_logs: storico dedicato dei tentativi di login falliti, con username tentato, IP sorgente, stadio del fallimento e motivo tecnico

Configurazione applicativa

La tabella app_config conserva impostazioni modificabili da UI.

Sezione mail:

  • host
  • port
  • username
  • password
  • from_email
  • from_name
  • use_tls
  • use_ssl
  • reply_to
  • timeout_seconds

Sezione patient_export_mail:

  • body_template

Sezioni UI:

  • ui_labels_meta
  • ui_labels

Sezione security:

  • login_ip_blacklist: IP o reti CIDR non autorizzate al login, una voce per riga
  • session_default_hours: timeout sessione globale usato quando l'utente non ha un valore dedicato
  • web_login_rate_limit: numero massimo di login web per finestra temporale
  • web_login_rate_window_seconds: finestra temporale del rate limit login web
  • api_auth_rate_limit: numero massimo di richieste token API per finestra temporale
  • api_auth_rate_window_seconds: finestra temporale del rate limit autenticazione API
  • password_reset_rate_limit: numero massimo di richieste reset password per finestra temporale
  • password_reset_rate_window_seconds: finestra temporale del rate limit reset password

Per il pannello dedicato ai rate limit di autenticazione, i valori consigliati in ambienti con IP pubblico condiviso sono:

Scenario Web login API auth Password reset
20 utenti 40 / 600s 40 / 600s 10 / 1800s
40 utenti 80 / 600s 80 / 600s 20 / 1800s
80 utenti 160 / 600s 160 / 600s 40 / 1800s

Questi valori servono a ridurre i falsi positivi in strutture con molti operatori dietro lo stesso IP NAT, mantenendo comunque il controllo sugli accessi anomali.

I segreti di configurazione possono essere memorizzati in uno store JSON separato:

.config_secrets.json

Il file viene scritto con permessi 0600 quando possibile.

Dati sensibili

CartClin tratta dati sanitari e identificativi. Sono particolarmente sensibili:

  • anagrafica pazienti
  • codice fiscale
  • note cliniche
  • diario paziente
  • eventi sanitari
  • esami clinici
  • rilevazioni glicemia e pressione
  • PDF scontrini/farmacia
  • email medico
  • token API
  • reset token
  • codici MFA temporanei
  • configurazioni SMTP

Indicazioni:

  • non versionare database SQLite reali
  • non versionare .flask_secret
  • non versionare .config_secrets.json
  • non inviare token API in log o chat
  • proteggere backup dei database con lo stesso livello dei dati di produzione
  • verificare periodicamente utenti inattivi e token scaduti
  • limitare permessi degli utenti non admin con assignments e authorizations

Note di coerenza

  • users.password contiene hash PBKDF2 locali, non credenziali LDAP.
  • L'autenticazione applicativa web non dipende da LDAP.
  • authorizations.perm e' la colonna moderna; alcune funzioni legacy citano permission.
  • assignments e' la tabella usata dai servizi paziente correnti.
  • patient_assignments esiste nello schema ma non e' la tabella principale usata dal codice.
  • Eventuali file farma_*.db legacy non fanno parte del modello scontrini corrente e non sono richiesti dal nuovo codice.
  • Le interpretazioni degli esami clinici derivano dal catalogo e dai range configurati; non sostituiscono valutazione medica.