Salta al contenuto principale

00 - Dominio Assicurativo per Developer: Prodotti, Attori e Data Model

Il Dominio Assicurativo per Developer: Prodotti, Attori e Modelli Dati Se sei uno sviluppatore software che si avvicina per la prima volta al mondo...

Cosa ne pensi di questo articolo?

00 - Dominio Assicurativo per Developer: Prodotti, Attori e Data Model
InsurTechFoto:Ruben BoekelooPexels

In Breve

Il Dominio Assicurativo per Developer: Prodotti, Attori e Modelli Dati Se sei uno sviluppatore software che si avvicina per la prima volta al mondo...

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.

Catena del Valore - Flusso Logico
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

TypeScript - Modello Dati del Dominio Assicurativo
// ============================================
// 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.

TypeScript - State Machine del Ciclo di Vita Polizza
// ============================================
// 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.

TypeScript - Claims State Machine e Modello Dati
// ============================================
// 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.

TypeScript - Rating Engine Semplificato
// ============================================
// 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 - Piattaforma Assicurativa
// ============================================
// 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.

TypeScript - Domain Events Assicurativi
// ============================================
// 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 quoteRequestId e notifica via webhook al completamento
  • Versioning temporale: Ogni risorsa (polizza, copertura) ha una dimensione temporale. L'API supporta query per asOfDate per recuperare lo stato storico
  • Idempotenza: Le operazioni di bind e payment devono essere idempotenti tramite idempotencyKey per 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

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti