Il Dominio Assicurativo per Developer: Prodotti, Attori e Modelli Dati
Se sei uno sviluppatore software che si avvicina per la prima volta al mondo assicurativo, probabilmente ti troverai davanti a un gergo impenetrabile: underwriting, endorsement, FNOL, subrogation, bordereaux. Non preoccuparti: questa guida traduce l'intero dominio assicurativo in concetti, modelli dati e pattern architetturali che un developer possa comprendere, implementare e soprattutto modellare correttamente in codice.
L'industria assicurativa muove globalmente oltre 7.000 miliardi di dollari di premi annui (dato 2025, Swiss Re Sigma) ed e uno dei settori più regolamentati al mondo. Eppure, gran parte dei sistemi informativi che la sostengono risale agli anni '80 e '90: mainframe COBOL, batch notturni, interfacce green-screen. La trasformazione digitale del settore, nota come InsurTech, sta ridisegnando tutto questo, e i developer sono al centro del cambiamento.
Questo articolo inaugura la serie InsurTech Engineering con una panoramica completa del dominio: i prodotti assicurativi, gli attori della catena del valore, i modelli dati fondamentali, il ciclo di vita di polizza e sinistro, e i pattern architetturali moderni per costruire piattaforme assicurative cloud-native.
Cosa Imparerai in Questo Articolo
- Le categorie di prodotti assicurativi (Vita, Danni, Salute, Specialty) e le loro differenze tecniche
- Gli attori della catena del valore: contraente, assicuratore, broker, agente, riassicuratore, regolatore
- La catena del valore assicurativa: distribuzione, underwriting, gestione polizze, sinistri, investimenti
- I modelli dati fondamentali: Policy, Claim, Premium, Coverage, Endorsement, Rider
- Il ciclo di vita completo della polizza: quotazione, emissione, variazione, rinnovo, cancellazione
- Il ciclo di vita del sinistro: FNOL, valutazione, liquidazione, recupero
- Il Domain-Driven Design applicato alle assicurazioni: bounded context e aggregati
- L'architettura del rating engine e il calcolo dei premi
- Standard ACORD e pattern API per l'interoperabilità
- Il panorama regolamentare: Solvency II, IFRS 17, GDPR
L'Industria Assicurativa: Una Panoramica per Developer
Prima di scrivere una singola riga di codice, e fondamentale capire come funziona il business assicurativo. A differenza di un e-commerce dove il prodotto e tangibile, nelle assicurazioni il "prodotto" e una promessa: il pagamento di un indennizzo futuro al verificarsi di un evento incerto. Questo rende il dominio intrinsecamente complesso dal punto di vista della modellazione dati.
"L'assicurazione e l'unico prodotto che si compra sperando di non usarlo mai. Questo paradosso definisce l'intera architettura dei sistemi che lo gestiscono."
Il Principio Fondamentale: Mutualita del Rischio
Il concetto cardine e la mutualita del rischio (risk pooling): un grande gruppo di persone o aziende contribuisce con premi regolari a un fondo comune, dal quale vengono prelevate le risorse per risarcire i pochi che subiscono un danno. Il ruolo dell'assicuratore e gestire questo fondo in modo attuarialmente sostenibile, garantendo che i premi raccolti siano sufficienti a coprire i sinistri attesi più i costi operativi e un margine di profitto.
Categorie di Prodotti Assicurativi
I prodotti assicurativi si dividono in macro-categorie con caratteristiche tecniche profondamente diverse. Comprendere queste differenze e cruciale per modellare correttamente i dati.
| Categoria | Esempi | Durata Tipica | Natura del Rischio | Complessità Dati |
|---|---|---|---|---|
| Vita (Life) | Termine, Mista, Unit-Linked, Pensione | 10-40 anni | Mortalita, longevita | Alta (tavole attuariali, riserve matematiche) |
| Danni (P&C) | Auto, Casa, RC Professionale, Incendio | 1 anno (rinnovabile) | Proprietà, responsabilità civile | Media (frequenza sinistri, costo medio) |
| Salute (Health) | Rimborso Spese, Infortuni, LTC | 1 anno / pluriennale | Morbilita, invalidita | Alta (codifiche ICD, DRG, reti sanitarie) |
| Specialty | Marine, Aviation, Cyber, D&O, E&O | Variabile | Rischi complessi / catastrofali | Molto alta (modelli CAT, accumuli) |
Implicazione per il Developer
Non esiste un singolo modello dati "universale" per le assicurazioni. Un sistema Life gestisce riserve matematiche e tavole di mortalita; un sistema P&C gestisce franchigie, massimali e perizie; un sistema Health gestisce codici medici e reti di provider. La scelta architetturale tra un modello unificato e modelli specializzati per LOB (Line of Business) e una delle decisioni più critiche nella progettazione di una piattaforma assicurativa.
Gli Attori della Catena del Valore
L'ecosistema assicurativo coinvolge numerosi attori con ruoli distinti. Ognuno di essi diventa un'entità nel nostro modello dati e spesso un bounded context separato nell'architettura.
Mappa degli Attori Principali
| Attore | Ruolo nel Dominio | Entità Dati Chiave | Interazioni Principali |
|---|---|---|---|
| Contraente (Policyholder) | Acquista la polizza, paga i premi | Customer, Account, PaymentMethod | Quote, Bind, Pay Premium, File Claim |
| Assicurato (Insured) | Persona/cosa coperta dalla polizza | InsuredParty, RiskObject | Può differire dal Contraente |
| Assicuratore (Insurer / Carrier) | Assume il rischio, paga i sinistri | Company, Portfolio, Reserve | Underwrite, Issue, Settle Claims |
| Agente | Rappresenta l'assicuratore, vende polizze | Agent, Agency, Commission | Distribute, Quote, Service |
| Broker | Rappresenta il cliente, negozia condizioni | Broker, BrokerFirm, Placement | Place Risk, Negotiate Terms |
| Riassicuratore (Reinsurer) | Assicura l'assicuratore (rischi in eccesso) | Treaty, Cession, Recovery | Cede, Retrocede, Settle |
| Perito (Adjuster) | Valuta i sinistri e determina l'indennizzo | Assessment, Estimate, Report | Inspect, Assess, Recommend |
| Regolatore (Regulator) | Supervisiona il mercato, impone regole | Filing, Compliance, Report | Approve Products, Audit, Fine |
Relazione Critica: Contraente vs Assicurato vs Beneficiario
Una delle complessità più sottovalutate e la distinzione tra contraente, assicurato e beneficiario. Nel caso più semplice (polizza auto individuale), le tre figure coincidono. Ma in una polizza vita aziendale, il contraente e l'azienda, gli assicurati sono i dipendenti, e i beneficiari sono i familiari designati. Il modello dati deve supportare questa flessibilità con relazioni many-to-many tra queste entità.
La Catena del Valore Assicurativa
La catena del valore assicurativa descrive l'intero flusso di attivita dal primo contatto con il cliente fino alla liquidazione del sinistro e al rinnovo della polizza. Ogni anello della catena corrisponde tipicamente a un bounded context nell'architettura software.
Distribution Underwriting Policy Admin Claims Investment
| | | | |
v v v v v
+-----------+ +-----------+ +------------+ +-----------+ +-----------+
| Marketing | | Risk | | Issue | | FNOL | | Asset |
| Lead Gen | | Selection | | Endorse | | Assess | | Mgmt |
| Quoting | | Pricing | | Renew | | Adjust | | ALM |
| Binding | | Approval | | Cancel | | Settle | | Reserves |
+-----------+ +-----------+ +------------+ +-----------+ +-----------+
| | | | |
+-------+-------+--------+-------+------+-------+-------+------+
| | | |
+---------+ +---------+ +---------+ +---------+
|Reinsur. | | Billing | | Fraud | | Report |
|Cessions | | Collect | | Detect | | Regulat.|
+---------+ +---------+ +---------+ +---------+
1. Distribuzione
La distribuzione comprende tutti i canali attraverso cui i prodotti assicurativi raggiungono il cliente: agenti (monomandatari o plurimandatari), broker, bancassurance, comparatori online e canali diretti (web, app, call center). Per il developer, questo si traduce in API di quotazione multi-canale, CRM integrati e motori di configurazione prodotto.
2. Underwriting (Assunzione del Rischio)
L'underwriting e il processo con cui l'assicuratore valuta il rischio proposto e decide se accettarlo, a quali condizioni e a quale prezzo. E il cuore tecnico del business assicurativo e coinvolge:
- Risk Assessment: Valutazione delle caratteristiche del rischio (eta, salute, ubicazione, storico sinistri)
- Rating: Calcolo del premio tramite il rating engine (algoritmi attuariali + regole di business)
- Risk Selection: Decisione di accettare, rifiutare o modificare le condizioni
- Referral: Escalation a underwriter senior per rischi fuori dai parametri automatici
3. Gestione Polizze (Policy Administration)
Il Policy Administration System (PAS) e il sistema centrale che gestisce l'intero ciclo di vita della polizza: emissione, variazioni (endorsement), rinnovi, cancellazioni e reinstatement. E tipicamente il sistema più complesso dell'ecosistema IT assicurativo.
4. Gestione Sinistri (Claims Management)
Il claims management copre tutto il processo dalla notifica del sinistro (FNOL - First Notice of Loss) fino alla liquidazione e all'eventuale recupero (surrogazione). E il processo che impatta direttamente la soddisfazione del cliente e la redditivita dell'assicuratore.
5. Investimenti e Gestione Riserve
Gli assicuratori investono i premi raccolti in attesa di pagare i sinistri futuri. La gestione degli investimenti (Asset-Liability Management) e il calcolo delle riserve tecniche sono processi regolamentati che richiedono modelli attuariali sofisticati.
I Modelli Dati Fondamentali
Entriamo nel vivo di ciò che un developer deve modellare. I seguenti sono gli aggregati (nel senso DDD) fondamentali di qualsiasi piattaforma assicurativa.
Entità Principali e Relazioni
// ============================================
// Core Insurance Domain Model (TypeScript)
// ============================================
/** Tipologia di prodotto assicurativo */
type LineOfBusiness = 'LIFE' | 'PROPERTY' | 'CASUALTY' | 'HEALTH' | 'MARINE' | 'CYBER';
/** Stato della polizza nel suo ciclo di vita */
type PolicyStatus =
| 'QUOTE' // Preventivo
| 'APPLICATION' // Proposta
| 'BOUND' // Vincolata (impegno assunto)
| 'ISSUED' // Emessa
| 'IN_FORCE' // In vigore
| 'SUSPENDED' // Sospesa
| 'LAPSED' // Decaduta (mancato pagamento)
| 'CANCELLED' // Cancellata
| 'EXPIRED' // Scaduta
| 'NON_RENEWED'; // Non rinnovata
/** Aggregato principale: la Polizza */
interface Policy {
readonly id: string;
readonly policyNumber: string;
readonly version: number; // Versioning per endorsement
readonly lineOfBusiness: LineOfBusiness;
readonly status: PolicyStatus;
readonly effectiveDate: Date;
readonly expirationDate: Date;
readonly inceptionDate: Date; // Data prima emissione
readonly policyholder: Party; // Contraente
readonly insuredParties: readonly InsuredParty[];
readonly coverages: readonly Coverage[];
readonly premium: PremiumBreakdown;
readonly endorsements: readonly Endorsement[];
readonly documents: readonly Document[];
readonly underwritingInfo: UnderwritingInfo;
readonly createdAt: Date;
readonly updatedAt: Date;
}
/** Parte coinvolta (persona fisica o giuridica) */
interface Party {
readonly id: string;
readonly type: 'INDIVIDUAL' | 'ORGANIZATION';
readonly firstName?: string;
readonly lastName?: string;
readonly companyName?: string;
readonly taxId: string; // Codice fiscale / P.IVA
readonly dateOfBirth?: Date;
readonly addresses: readonly Address[];
readonly contacts: readonly ContactInfo[];
readonly riskProfile?: RiskProfile;
}
/** Soggetto assicurato con specifico ruolo */
interface InsuredParty {
readonly party: Party;
readonly role: 'PRIMARY' | 'ADDITIONAL' | 'NAMED_INSURED';
readonly relationship: string; // Relazione col contraente
}
/** Copertura: cosa e protetto e fino a quanto */
interface Coverage {
readonly id: string;
readonly code: string; // Es: "TPL", "CASCO", "FIRE"
readonly name: string;
readonly description: string;
readonly type: 'BASE' | 'OPTIONAL' | 'MANDATORY';
readonly limit: Money; // Massimale
readonly deductible: Deductible; // Franchigia
readonly premium: Money; // Premio per questa copertura
readonly effectiveDate: Date;
readonly expirationDate: Date;
readonly exclusions: readonly string[];
readonly conditions: readonly string[];
}
/** Franchigia con diverse modalità di applicazione */
interface Deductible {
readonly type: 'FIXED' | 'PERCENTAGE' | 'WAITING_PERIOD' | 'AGGREGATE';
readonly amount?: Money; // Per FIXED
readonly percentage?: number; // Per PERCENTAGE
readonly waitingDays?: number; // Per WAITING_PERIOD
readonly aggregateLimit?: Money; // Per AGGREGATE
readonly appliesToEach: 'CLAIM' | 'OCCURRENCE' | 'POLICY_PERIOD';
}
/** Scomposizione del premio */
interface PremiumBreakdown {
readonly grossPremium: Money; // Premio lordo
readonly netPremium: Money; // Premio netto (per l'assicuratore)
readonly taxes: Money; // Imposte
readonly fees: Money; // Diritti e commissioni
readonly commission: Money; // Provvigione intermediario
readonly components: readonly PremiumComponent[];
readonly paymentPlan: PaymentPlan;
}
/** Variazione contrattuale in corso di polizza */
interface Endorsement {
readonly id: string;
readonly endorsementNumber: number;
readonly type: 'COVERAGE_CHANGE' | 'LIMIT_CHANGE' | 'ADD_INSURED'
| 'REMOVE_INSURED' | 'ADDRESS_CHANGE' | 'VEHICLE_CHANGE'
| 'GENERAL_CHANGE';
readonly effectiveDate: Date;
readonly description: string;
readonly premiumAdjustment: Money; // Differenza premio (+/-)
readonly previousVersion: number;
readonly newVersion: number;
readonly changes: readonly FieldChange[];
readonly approvedBy?: string;
readonly approvedAt?: Date;
}
/** Valore monetario con valuta */
interface Money {
readonly amount: number;
readonly currency: string; // ISO 4217: "EUR", "USD", "GBP"
}
/** Singola modifica tracciata nell'endorsement */
interface FieldChange {
readonly field: string;
readonly oldValue: string;
readonly newValue: string;
}
Pattern Chiave: Immutabilita e Versioning
Nota come ogni interfaccia usa readonly su tutte le proprietà. Nel dominio assicurativo,
la tracciabilita e un requisito regolamentare: ogni modifica a una polizza genera
un nuovo endorsement che incrementa la version. Non si "modifica" mai
una polizza; si crea una nuova versione. Questo pattern si sposa perfettamente con l'event sourcing
e con architetture CQRS.
Il Ciclo di Vita della Polizza
La polizza attraversa stati ben definiti durante la sua esistenza. Modelliamo questo ciclo di vita come una state machine, un pattern fondamentale nel software assicurativo.
// ============================================
// Policy Lifecycle State Machine
// ============================================
/** Transizioni valide nel ciclo di vita della polizza */
type PolicyTransition =
| { from: 'QUOTE'; to: 'APPLICATION'; action: 'SUBMIT_APPLICATION' }
| { from: 'QUOTE'; to: 'CANCELLED'; action: 'DECLINE_QUOTE' }
| { from: 'APPLICATION'; to: 'BOUND'; action: 'BIND_COVERAGE' }
| { from: 'APPLICATION'; to: 'CANCELLED'; action: 'DECLINE_APPLICATION' }
| { from: 'BOUND'; to: 'ISSUED'; action: 'ISSUE_POLICY' }
| { from: 'ISSUED'; to: 'IN_FORCE'; action: 'ACTIVATE' }
| { from: 'IN_FORCE'; to: 'IN_FORCE'; action: 'ENDORSE' }
| { from: 'IN_FORCE'; to: 'SUSPENDED'; action: 'SUSPEND' }
| { from: 'IN_FORCE'; to: 'CANCELLED'; action: 'CANCEL' }
| { from: 'IN_FORCE'; to: 'EXPIRED'; action: 'EXPIRE' }
| { from: 'IN_FORCE'; to: 'IN_FORCE'; action: 'RENEW' }
| { from: 'IN_FORCE'; to: 'NON_RENEWED'; action: 'NON_RENEW' }
| { from: 'SUSPENDED'; to: 'IN_FORCE'; action: 'REINSTATE' }
| { from: 'SUSPENDED'; to: 'LAPSED'; action: 'LAPSE' }
| { from: 'LAPSED'; to: 'IN_FORCE'; action: 'REINSTATE' }
| { from: 'LAPSED'; to: 'CANCELLED'; action: 'CANCEL' };
/** Mappa delle transizioni valide per validazione runtime */
const VALID_TRANSITIONS: ReadonlyMap<PolicyStatus, readonly PolicyTransition[]> = new Map([
['QUOTE', [
{ from: 'QUOTE', to: 'APPLICATION', action: 'SUBMIT_APPLICATION' },
{ from: 'QUOTE', to: 'CANCELLED', action: 'DECLINE_QUOTE' },
]],
['APPLICATION', [
{ from: 'APPLICATION', to: 'BOUND', action: 'BIND_COVERAGE' },
{ from: 'APPLICATION', to: 'CANCELLED', action: 'DECLINE_APPLICATION' },
]],
['IN_FORCE', [
{ from: 'IN_FORCE', to: 'IN_FORCE', action: 'ENDORSE' },
{ from: 'IN_FORCE', to: 'SUSPENDED', action: 'SUSPEND' },
{ from: 'IN_FORCE', to: 'CANCELLED', action: 'CANCEL' },
{ from: 'IN_FORCE', to: 'EXPIRED', action: 'EXPIRE' },
{ from: 'IN_FORCE', to: 'IN_FORCE', action: 'RENEW' },
{ from: 'IN_FORCE', to: 'NON_RENEWED', action: 'NON_RENEW' },
]],
]);
/** Funzione pura per la transizione di stato */
function transitionPolicy(
policy: Policy,
action: PolicyTransition['action'],
context: TransitionContext
): Policy {
const validTransitions = VALID_TRANSITIONS.get(policy.status);
const transition = validTransitions?.find(t => t.action === action);
if (!transition) {
throw new InvalidTransitionError(
`Cannot perform ${action} on policy in status ${policy.status}`
);
}
// Crea nuova versione immutabile della polizza
return {
...policy,
status: transition.to,
version: policy.version + 1,
updatedAt: new Date(),
endorsements: action === 'ENDORSE'
? [...policy.endorsements, context.endorsement!]
: policy.endorsements,
};
}
Fasi Chiave del Ciclo di Vita
Fase Pre-Emissione
- Quote: Preventivo indicativo basato su dati minimi. Validita tipica: 30 giorni
- Application: Proposta formale con tutti i dati necessari per l'underwriting
- Bind: L'assicuratore si impegna a fornire copertura (ma la polizza non e ancora emessa)
- Issue: Emissione del documento di polizza ufficiale
Fase Post-Emissione
- Endorse: Modifica delle condizioni in corso di validita (nuova versione)
- Renew: Rinnovo alla scadenza (può comportare re-rating)
- Suspend: Sospensione temporanea (es. mancato pagamento)
- Cancel: Cancellazione con calcolo del premio di rateo
- Reinstate: Ripristino dopo sospensione o decadenza
Il Ciclo di Vita del Sinistro (Claims Lifecycle)
Il sinistro e l'evento che attiva la promessa assicurativa. Il suo ciclo di vita e altrettanto strutturato e si presta perfettamente alla modellazione come state machine.
// ============================================
// Claims Domain Model
// ============================================
type ClaimStatus =
| 'FNOL' // First Notice of Loss - notifica iniziale
| 'REGISTERED' // Registrato nel sistema
| 'UNDER_INVESTIGATION' // In fase di indagine/perizia
| 'ASSESSED' // Valutato dal perito
| 'APPROVED' // Approvato per liquidazione
| 'PARTIALLY_APPROVED'// Parzialmente approvato
| 'DENIED' // Rifiutato
| 'SETTLED' // Liquidato
| 'REOPENED' // Riaperto
| 'CLOSED' // Chiuso definitivamente
| 'SUBROGATION'; // In fase di recupero
interface Claim {
readonly id: string;
readonly claimNumber: string;
readonly policyId: string;
readonly policyNumber: string;
readonly status: ClaimStatus;
readonly lossDate: Date; // Data del sinistro
readonly reportDate: Date; // Data della denuncia
readonly lossType: string; // Tipo di danno
readonly lossDescription: string;
readonly lossLocation: Address;
readonly claimant: Party; // Chi richiede l'indennizzo
readonly reserves: readonly Reserve[];
readonly payments: readonly ClaimPayment[];
readonly assessments: readonly Assessment[];
readonly documents: readonly Document[];
readonly fraudIndicators: readonly FraudIndicator[];
readonly totalIncurred: Money; // Riserva + Pagato
readonly totalPaid: Money;
readonly totalReserve: Money;
}
/** Riserva: stima del costo futuro del sinistro */
interface Reserve {
readonly id: string;
readonly type: 'INDEMNITY' | 'EXPENSE' | 'LEGAL';
readonly amount: Money;
readonly setDate: Date;
readonly setBy: string;
readonly reason: string;
readonly history: readonly ReserveChange[];
}
/** Pagamento effettuato sul sinistro */
interface ClaimPayment {
readonly id: string;
readonly type: 'INDEMNITY' | 'EXPENSE' | 'LEGAL' | 'SALVAGE' | 'SUBROGATION';
readonly amount: Money;
readonly payee: Party;
readonly paymentDate: Date;
readonly paymentMethod: string;
readonly invoiceReference?: string;
readonly approvedBy: string;
}
/** Valutazione peritale */
interface Assessment {
readonly id: string;
readonly assessor: Party; // Perito
readonly assessmentDate: Date;
readonly damageEstimate: Money;
readonly findings: string;
readonly recommendation: 'APPROVE' | 'DENY' | 'FURTHER_INVESTIGATION';
readonly photos: readonly string[]; // URL delle foto
readonly report: Document;
}
/** Indicatore di potenziale frode */
interface FraudIndicator {
readonly rule: string;
readonly score: number; // 0-100
readonly description: string;
readonly triggeredAt: Date;
}
Le Fasi del Sinistro nel Dettaglio
| Fase | Attivita | Attori Coinvolti | Dati Generati |
|---|---|---|---|
| FNOL | Denuncia del sinistro via telefono, web, app, email | Assicurato, Call Center | ClaimNotification, InitialReserve |
| Triage | Classificazione del sinistro, assegnazione priorità, verifica copertura | Claims Handler, Sistema automatico | CoverageVerification, Priority, Assignment |
| Investigation | Raccolta documentazione, perizia, verifica circostanze | Perito, Investigatore, Medico legale | Assessment, Photos, ExpertReport |
| Adjudication | Decisione: accoglimento totale, parziale o rigetto | Claims Manager, Comitato sinistri | Decision, AdjustmentCalc |
| Settlement | Calcolo dell'indennizzo e pagamento | Claims Handler, Ufficio pagamenti | Payment, SettlementAgreement |
| Recovery | Surrogazione verso terzi responsabili, recupero salvage | Ufficio legale, Ufficio recuperi | SubrogationClaim, Recovery |
L'Architettura del Rating Engine
Il rating engine e il componente che calcola il premio assicurativo. E uno dei sistemi più critici e performanti dell'ecosistema InsurTech: deve elaborare migliaia di quotazioni al secondo con precisione attuariale e tracciabilita completa.
Come Funziona il Calcolo del Premio
Il calcolo del premio segue una pipeline ben definita che trasforma i fattori di rischio in un prezzo finale. Vediamo un esempio semplificato per l'RC Auto.
// ============================================
// Rating Engine - Esempio RC Auto
// ============================================
/** Fattori di rischio per la tariffazione auto */
interface AutoRatingFactors {
readonly driverAge: number;
readonly driverExperience: number; // Anni di patente
readonly vehicleGroup: number; // Gruppo tariffario 1-20
readonly vehicleAge: number;
readonly postalCode: string;
readonly claimsHistory: number; // Sinistri ultimi 5 anni
readonly bonusMalusClass: number; // Classe CU (1-18 in Italia)
readonly annualMileage: number;
readonly garaging: 'GARAGE' | 'STREET' | 'PARKING';
readonly usage: 'PERSONAL' | 'COMMUTE' | 'BUSINESS';
}
/** Risultato del calcolo tariffario */
interface RatingResult {
readonly baseRate: Money;
readonly factors: readonly AppliedFactor[];
readonly technicalPremium: Money; // Premio tecnico (puro rischio)
readonly loadings: readonly Loading[];
readonly grossPremium: Money; // Premio lordo finale
readonly taxes: Money;
readonly totalPremium: Money; // Totale da pagare
readonly ratingDate: Date;
readonly rateTableVersion: string;
readonly auditTrail: readonly string[];
}
interface AppliedFactor {
readonly name: string;
readonly inputValue: string | number;
readonly factor: number; // Moltiplicatore (es: 1.25 = +25%)
readonly source: string; // Tabella di riferimento
}
interface Loading {
readonly type: 'EXPENSE' | 'COMMISSION' | 'PROFIT' | 'CATASTROPHE' | 'REINSURANCE';
readonly percentage: number;
readonly amount: Money;
}
/** Rating Engine: funzione pura che calcola il premio */
function calculateAutoRate(
factors: AutoRatingFactors,
rateTables: RateTableSet
): RatingResult {
const auditTrail: string[] = [];
// 1. Base Rate dalla tabella territoriale
const baseRate = rateTables.territorial.lookup(factors.postalCode);
auditTrail.push(`Base rate for ${factors.postalCode}: ${baseRate}`);
// 2. Applicazione fattori moltiplicativi
const ageMultiplier = rateTables.ageFactors.lookup(factors.driverAge);
const vehicleMultiplier = rateTables.vehicleGroups.lookup(factors.vehicleGroup);
const bonusMalusMultiplier = rateTables.bonusMalus.lookup(factors.bonusMalusClass);
const experienceMultiplier = rateTables.experience.lookup(factors.driverExperience);
const mileageMultiplier = rateTables.mileage.lookup(factors.annualMileage);
const appliedFactors: AppliedFactor[] = [
{ name: 'Age', inputValue: factors.driverAge, factor: ageMultiplier, source: 'AGE_TABLE_v3' },
{ name: 'Vehicle Group', inputValue: factors.vehicleGroup, factor: vehicleMultiplier, source: 'VEH_TABLE_v2' },
{ name: 'Bonus/Malus', inputValue: factors.bonusMalusClass, factor: bonusMalusMultiplier, source: 'BM_TABLE_v1' },
{ name: 'Experience', inputValue: factors.driverExperience, factor: experienceMultiplier, source: 'EXP_TABLE_v1' },
{ name: 'Mileage', inputValue: factors.annualMileage, factor: mileageMultiplier, source: 'KM_TABLE_v2' },
];
// 3. Premio tecnico = base * prodotto dei fattori
const combinedFactor = appliedFactors.reduce((acc, f) => acc * f.factor, 1);
const technicalPremium = baseRate * combinedFactor;
auditTrail.push(`Technical premium: ${baseRate} * ${combinedFactor.toFixed(4)} = ${technicalPremium.toFixed(2)}`);
// 4. Caricamenti (expense loading, commissioni, profitto)
const loadings: Loading[] = [
{ type: 'EXPENSE', percentage: 0.15, amount: { amount: technicalPremium * 0.15, currency: 'EUR' } },
{ type: 'COMMISSION', percentage: 0.12, amount: { amount: technicalPremium * 0.12, currency: 'EUR' } },
{ type: 'PROFIT', percentage: 0.05, amount: { amount: technicalPremium * 0.05, currency: 'EUR' } },
{ type: 'CATASTROPHE', percentage: 0.02, amount: { amount: technicalPremium * 0.02, currency: 'EUR' } },
];
const totalLoadingPct = loadings.reduce((acc, l) => acc + l.percentage, 0);
const grossPremium = technicalPremium * (1 + totalLoadingPct);
// 5. Imposte (22.25% per RC Auto in Italia)
const taxRate = 0.2225;
const taxes = grossPremium * taxRate;
const totalPremium = grossPremium + taxes;
return {
baseRate: { amount: baseRate, currency: 'EUR' },
factors: appliedFactors,
technicalPremium: { amount: technicalPremium, currency: 'EUR' },
loadings,
grossPremium: { amount: grossPremium, currency: 'EUR' },
taxes: { amount: taxes, currency: 'EUR' },
totalPremium: { amount: totalPremium, currency: 'EUR' },
ratingDate: new Date(),
rateTableVersion: 'RC_AUTO_2026_Q1',
auditTrail,
};
}
Architettura del Rating Engine Moderno
Un rating engine in produzione e molto più complesso di questo esempio. Le caratteristiche chiave includono:
- Rate Tables versionate: Ogni tabella tariffaria ha una data di validita (effective date). Il sistema deve applicare la tabella corretta in base alla data di effetto della polizza, non alla data corrente
- Rule Engine separato: Le regole di business (limiti, esclusioni, sconti) sono configurabili senza deploy del codice, tipicamente tramite un motore regole (Drools, RETE, o JSON-based)
- Audit trail completo: Ogni step del calcolo deve essere tracciabile per compliance regolamentare
- Scalabilità orizzontale: Il rating engine deve gestire picchi di migliaia di quotazioni al secondo (comparatori, open enrollment)
- Idempotenza: Lo stesso input deve sempre produrre lo stesso output (funzione pura)
Domain-Driven Design per le Assicurazioni
Il Domain-Driven Design (DDD) e l'approccio architetturale più adatto al dominio assicurativo per la sua complessità intrinseca e la necessità di allineare il software al linguaggio del business. Vediamo come applicarlo concretamente.
Bounded Context dell'Ecosistema Assicurativo
Ogni bounded context ha il proprio ubiquitous language, i propri modelli e le proprie regole. Il termine "polizza" ha significati diversi nel contesto Underwriting (proposta da valutare) rispetto a Policy Administration (contratto emesso).
// ============================================
// Bounded Context Map
// ============================================
//
// +------------------+ +------------------+ +------------------+
// | Distribution | | Underwriting | | Policy Admin |
// | | | | | |
// | - Lead | | - Submission | | - Policy |
// | - Opportunity |---->| - Risk |---->| - Coverage |
// | - Quote Request | | - Rating | | - Endorsement |
// | - Channel | | - Decision | | - Renewal |
// +------------------+ +------------------+ +------------------+
// | | |
// | | |
// v v v
// +------------------+ +------------------+ +------------------+
// | CRM / Party | | Reinsurance | | Claims |
// | | | | | |
// | - Customer | | - Treaty | | - Claim |
// | - Agent | | - Cession | | - Reserve |
// | - Broker | | - Recovery | | - Payment |
// | - Address | | - Bordereaux | | - Assessment |
// +------------------+ +------------------+ +------------------+
// | | |
// v v v
// +------------------+ +------------------+ +------------------+
// | Billing | | Compliance | | Fraud Detection |
// | | | | | |
// | - Invoice | | - Filing | | - Alert |
// | - Payment | | - Report | | - Investigation |
// | - Collection | | - Audit | | - Score |
// | - Installment | | - Solvency | | - Rule |
// +------------------+ +------------------+ +------------------+
// Context Mapping Relationships:
// Distribution --[Conformist]--> Underwriting
// Underwriting --[Published Language]--> Policy Admin
// Policy Admin --[Shared Kernel]--> Billing
// Policy Admin --[Customer/Supplier]--> Claims
// Claims --[Anti-Corruption Layer]--> Fraud Detection
// Underwriting --[Partnership]--> Reinsurance
// All Contexts --[Conformist]--> Compliance
Aggregati e Invarianti
In DDD, ogni aggregato protegge le proprie invarianti di business. Ecco le invarianti principali per i due aggregati chiave:
Aggregato Policy
- Una polizza deve avere almeno una copertura attiva
- La data di scadenza deve essere successiva alla data di effetto
- Il premio totale deve essere la somma dei premi delle coperture + caricamenti
- Ogni endorsement deve incrementare la versione
- Le transizioni di stato devono rispettare la state machine
- Non si può cancellare una polizza con sinistri aperti
Aggregato Claim
- La data del sinistro deve rientrare nel periodo di copertura della polizza
- La riserva non può essere negativa
- Il totale pagato non può superare il massimale di copertura
- Un sinistro chiuso non può ricevere nuovi pagamenti (va riaperto)
- La decisione richiede almeno una valutazione peritale
- Il pagamento richiede approvazione se supera la soglia di autorita
Domain Events
I domain events sono il meccanismo con cui i bounded context comunicano in modo disaccoppiato. Ogni evento rappresenta qualcosa di significativo che e accaduto nel dominio.
// ============================================
// Insurance Domain Events
// ============================================
interface DomainEvent {
readonly eventId: string;
readonly eventType: string;
readonly occurredAt: Date;
readonly aggregateId: string;
readonly aggregateType: string;
readonly version: number;
readonly correlationId: string;
readonly causationId?: string;
}
// --- Policy Events ---
interface PolicyQuoted extends DomainEvent {
readonly eventType: 'POLICY_QUOTED';
readonly aggregateType: 'Policy';
readonly quoteNumber: string;
readonly premium: Money;
readonly validUntil: Date;
}
interface PolicyIssued extends DomainEvent {
readonly eventType: 'POLICY_ISSUED';
readonly aggregateType: 'Policy';
readonly policyNumber: string;
readonly effectiveDate: Date;
readonly premium: Money;
readonly coverages: readonly string[];
}
interface PolicyEndorsed extends DomainEvent {
readonly eventType: 'POLICY_ENDORSED';
readonly aggregateType: 'Policy';
readonly endorsementNumber: number;
readonly changes: readonly FieldChange[];
readonly premiumAdjustment: Money;
}
// --- Claim Events ---
interface ClaimFiled extends DomainEvent {
readonly eventType: 'CLAIM_FILED';
readonly aggregateType: 'Claim';
readonly policyNumber: string;
readonly lossDate: Date;
readonly lossType: string;
readonly initialReserve: Money;
}
interface ClaimSettled extends DomainEvent {
readonly eventType: 'CLAIM_SETTLED';
readonly aggregateType: 'Claim';
readonly settlementAmount: Money;
readonly payee: string;
}
// --- Cross-Context Reactions ---
// PolicyIssued -> Billing: createInvoice()
// PolicyIssued -> Reinsurance: calculateCession()
// ClaimFiled -> FraudDetection: screenClaim()
// ClaimFiled -> Reinsurance: notifyCession()
// ClaimSettled -> Billing: adjustReserve()
// ClaimSettled -> Reinsurance: calculateRecovery()
Standard ACORD e Interoperabilità
ACORD (Association for Cooperative Operations Research and Development) e l'organizzazione che definisce gli standard di dati per l'industria assicurativa globale. Per un developer, ACORD e l'equivalente di HL7/FHIR per la sanita o SWIFT per la finanza.
ACORD Data Standards: Cosa Sono
ACORD fornisce modelli dati granulari, formati di messaggio (XML e JSON) e schemi progettati specificamente per i processi assicurativi. L'obiettivo e garantire il flusso efficiente dei dati tra tutti gli attori dell'ecosistema: assicuratori, broker, agenti, riassicuratori e regolatori.
| Standard ACORD | Formato | Utilizzo | Settore |
|---|---|---|---|
| ACORD AL3 | Proprietario (fixed-length) | Scambio dati agente-assicuratore (USA) | P&C Personal Lines |
| ACORD XML | XML Schema | Quotazione, emissione, sinistri, billing | P&C, Life, Health |
| ACORD GRLC 2.0 | JSON / XML | Riassicurazione e large commercial (global) | Reinsurance, Specialty |
| ACORD Next-Gen | JSON (API-first) | Microservizi, API REST, eventi asincroni | Cross-sector |
| ACORD Forms | PDF/XML | Moduli standardizzati (certificati, appendici) | P&C (USA) |
GRLC Generation 2.0 (Aprile 2025)
L'aggiornamento più significativo degli ultimi anni e il lancio di GRLC Generation 2.0, uno standard digital-first basato su JSON, ottimizzato per transazioni fine-grained come microservizi e API. Supporta l'elaborazione straight-through end-to-end dell'intero ciclo di vita della polizza nell'ecosistema riassicurativo globale, consentendo integrazioni moderne senza passare dai vecchi formati XML batch.
Pattern API per l'Assicurazione
Le API assicurative moderne seguono pattern specifici che riflettono la complessità del dominio:
- Quotazione asincrona: Le quotazioni complesse (commercial, specialty) richiedono elaborazione asincrona. L'API restituisce un
quoteRequestIde notifica via webhook al completamento - Versioning temporale: Ogni risorsa (polizza, copertura) ha una dimensione temporale. L'API supporta query per
asOfDateper recuperare lo stato storico - Idempotenza: Le operazioni di bind e payment devono essere idempotenti tramite
idempotencyKeyper evitare duplicazioni - Event streaming: I cambi di stato vengono notificati via eventi (webhook o message broker) per l'integrazione con sistemi downstream
Il Panorama Regolamentare
L'industria assicurativa e una delle più regolamentate al mondo. Per un developer, questo significa che molte decisioni architetturali sono dettate dalla compliance, non solo dalle best practice ingegneristiche.
Regolamenti Chiave e Impatto sul Software
| Regolamento | Ambito | Impatto sul Software |
|---|---|---|
| Solvency II | EU - Requisiti patrimoniali e di solvibilita | Modelli di rischio, calcolo SCR (Solvency Capital Requirement), reporting XBRL, data quality framework |
| IFRS 17 | Globale - Contabilizzazione contratti assicurativi | Calcolo CSM (Contractual Service Margin), raggruppamento contratti, measurement models (BBA, VFA, PAA) |
| GDPR / Privacy | EU - Protezione dati personali | Consenso granulare, diritto all'oblio vs retention obbligatoria (conflitto), pseudonimizzazione, DPIA |
| IDD | EU - Distribuzione assicurativa | Tracciabilita consulenza, adeguatezza prodotto, conflitti di interesse, documentazione pre-contrattuale |
| DORA | EU - Resilienza operativa digitale | ICT risk management, incident reporting, resilience testing, third-party risk (cloud provider) |
| ICS 2025 | Globale - Standard patrimoniale per IAIG | Calcolo del capitale regolamentare con standard globale unificato (operativo dal 2025) |
Il Conflitto GDPR vs Retention Assicurativa
Uno dei dilemmi più complessi per il developer assicurativo: il GDPR impone il diritto all'oblio, ma le normative assicurative richiedono la conservazione dei dati per periodi che vanno da 5 a 30 anni (sinistri con riserve aperte, contenziosi legali, obblighi attuariali). La soluzione tipica prevede pseudonimizzazione progressiva: i dati identificativi vengono separati dai dati transazionali e cancellati quando possibile, mantenendo i dati anonimizzati per gli obblighi regolamentari.
Architettura di una Piattaforma InsurTech Moderna
Le piattaforme assicurative moderne adottano un'architettura cloud-native, API-first, event-driven. Il monolite legacy viene scomposto in microservizi allineati ai bounded context del dominio.
Stack Tecnologico Tipico (2025-2026)
| Layer | Tecnologie | Funzione |
|---|---|---|
| Frontend | Angular, React, Vue + micro-frontend | Portal agente, portal cliente, backoffice |
| API Gateway | Kong, AWS API Gateway, Apigee | Rate limiting, auth, routing, versioning |
| Microservizi | Node.js/NestJS, Java/Spring Boot, Go | Policy, Claims, Rating, Billing, CRM |
| Event Bus | Apache Kafka, AWS EventBridge, RabbitMQ | Domain events, CQRS, event sourcing |
| Database | PostgreSQL, MongoDB, DynamoDB | Database per servizio (database per bounded context) |
| AI/ML | Python, TensorFlow, SageMaker | Fraud detection, pricing optimization, OCR documenti |
| Orchestrazione | Kubernetes, AWS ECS, Temporal.io | Scaling, saga pattern, workflow di lunga durata |
| Observability | Datadog, Grafana, OpenTelemetry | Tracing distribuito, metriche, logging centralizzato |
Pattern Architetturali Chiave
Event Sourcing per le Polizze
L'event sourcing e particolarmente adatto al dominio assicurativo perchè la polizza e intrinsecamente una sequenza di eventi (emissione, endorsement, rinnovo, sinistro). Invece di memorizzare solo lo stato corrente, si memorizzano tutti gli eventi e si ricostruisce lo stato corrente tramite replay. Questo fornisce automaticamente un audit trail completo, un requisito regolamentare fondamentale.
Saga Pattern per i Processi Cross-Context
Processi come l'emissione di una polizza coinvolgono più bounded context: Underwriting approva, Policy Admin emette, Billing crea la fattura, Reinsurance calcola la cessione. Il saga pattern (orchestrato o coreografato) coordina questi step distribuiti garantendo consistenza eventuale e compensazione in caso di fallimento. Temporal.io e particolarmente popolare nell'InsurTech per implementare workflow di lunga durata con stato persistente.
Multi-Agent AI Systems (Trend 2026)
Invece di un singolo assistente AI monolitico, le piattaforme InsurTech più avanzate stanno implementando sistemi multi-agente con agenti specializzati: un agente per l'intake dei sinistri, uno per il fraud check, uno per le comunicazioni al cliente, uno per i pagamenti e il recupero. Questi agenti sono orchestrati attraverso workflow chiari e collaborano per automatizzare l'intero ciclo di vita del sinistro.
Conclusioni e Prossimi Passi
Il dominio assicurativo e uno dei più ricchi e complessi che un developer possa affrontare. In questo articolo abbiamo costruito le fondamenta: i prodotti, gli attori, la catena del valore, i modelli dati, i cicli di vita, il rating engine, il DDD applicato e il panorama regolamentare.
Ecco i takeaway principali:
- Il prodotto assicurativo e una promessa: questo rende i modelli dati intrinsecamente temporali e versionati
- Non esiste un modello universale: Life, P&C, Health e Specialty hanno esigenze profondamente diverse
- La state machine e il pattern fondamentale: sia per le polizze che per i sinistri, il ciclo di vita e una macchina a stati con transizioni ben definite
- L'immutabilita e un requisito regolamentare: ogni modifica genera una nuova versione, mai una sovrascrittura
- Il DDD e l'approccio naturale: bounded context allineati alla catena del valore, aggregati che proteggono invarianti di business, domain events per il disaccoppiamento
- La compliance guida l'architettura: Solvency II, IFRS 17, GDPR e DORA non sono "nice to have" ma vincoli architetturali primari
- ACORD e la lingua franca: gli standard ACORD (specialmente Next-Gen JSON) sono essenziali per l'interoperabilità nell'ecosistema
Nella Prossima Puntata
Nel prossimo articolo della serie InsurTech Engineering approfondiremo il Policy Administration System: come progettare un PAS moderno con product configurator, versioning temporale, endorsement engine e integrazione con il rating engine. Vedremo pattern concreti per gestire la complessità dei prodotti assicurativi multi-coverage con un approccio domain-driven.

Commenti
Caricamento commenti...
Accedi per commentare