Het verzekeringsdomein voor ontwikkelaars: producten, actoren en datamodellen
Als u een softwareontwikkelaar bent die nieuw is in de verzekeringswereld, waarschijnlijk je wordt geconfronteerd met ondoordringbaar jargon: acceptatie, aanbeveling, FNOL, subrogatie, bordereau. Maak je geen zorgen: deze gids vertaalt het hele domein verzekering in concepten, datamodellen en architecturale patronen die een ontwikkelaar kan begrijpen, implementeren en vooral correct modelleren in code.
De verzekeringssector gaat wereldwijd vooruit 7 biljoen dollar aan jaarlijkse premies (gegevens 2025, Swiss Re Sigma) en is een van de meest gereguleerde sectoren ter wereld. Toch zijn de meeste informatiesystemen die dit ondersteunen dateren uit de jaren 80 en 90: COBOL-mainframes, nachtelijke batches, green-screen-interfaces. De digitale transformatie van de industrie, bekend als VerzekerTech, is dit allemaal aan het herontwerpen, en ontwikkelaars staan in het middelpunt van de verandering.
Dit artikel luidt de serie in InsurTech-techniek met een compleet overzicht van het domein: verzekeringsproducten, spelers in de waardeketen, fundamentele datamodellen, de levenscyclus van beleid en claims, en moderne architecturale patronen voor het bouwen van platforms cloud-native verzekeringen.
Wat u in dit artikel leert
- De categorieën verzekeringsproducten (Leven, Niet-Leven, Ziekte, Specialiteit) en hun technische verschillen
- De spelers in de waardeketen: verzekeringnemer, verzekeraar, makelaar, agent, herverzekeraar, toezichthouder
- De verzekeringswaardeketen: distributie, acceptatie, polisbeheer, claims, beleggingen
- De fundamentele datamodellen: Beleid, Claim, Premium, Dekking, Goedkeuring, Rider
- De volledige levenscyclus van de polis: offerte, uitgifte, wijziging, verlenging, opzegging
- De levenscyclus van de claim: FNOL, evaluatie, afwikkeling, invordering
- Domain-Driven Design toegepast op verzekeringen: begrensde context en aggregaten
- De architectuur van de ratingengine en de berekening van premies
- ACORD-standaarden en API-patronen voor interoperabiliteit
- Het regelgevingslandschap: Solvabiliteit II, IFRS 17, AVG
De verzekeringssector: een overzicht van een ontwikkelaar
Voordat u ook maar één regel code schrijft, is het essentieel om dit te begrijpen hoe het bedrijf werkt verzekering. In tegenstelling tot e-commerce, waar het product tastbaar is, bij verzekeringen het "product" is een belofte: de betaling van toekomstige schadevergoeding bij het optreden van a onzekere gebeurtenis. Dit maakt het domein inherent complex vanuit het perspectief van datamodellering.
"Verzekeringen zijn het enige product dat je koopt in de hoop het nooit te gebruiken. Deze paradox definieert de volledige architectuur van de systemen die het beheren."
Het fundamentele principe: wederkerigheid van risico
Het sleutelbegrip is de risico op wederkerigheid (risicopooling): een geweldige een groep mensen of bedrijven draagt regelmatig premies bij aan een gemeenschappelijk fonds waaruit zij afkomstig zijn de middelen om de weinigen die schade lijden te compenseren. De rol van de verzekeraar en het managen hiervan op een actuarieel duurzame manier financieren, waarbij ervoor wordt gezorgd dat de geïnde premies voldoende zijn om de dekking te dekken verwachte claims plus bedrijfskosten en een winstmarge.
Verzekeringsproductcategorieën
Verzekeringsproducten zijn onderverdeeld in macrocategorieën met diepgaand verschillende technische kenmerken. Het begrijpen van deze verschillen is cruciaal om uw gegevens correct te kunnen modelleren.
| Categorie | Voorbeelden | Typische duur | Aard van het risico | Gegevenscomplexiteit |
|---|---|---|---|---|
| Leven (Leven) | Termijn, Gemengd, Unit-Linked, Bestuur | 10-40 jaar | Sterfte, levensduur | Hoog (actuariële tabellen, wiskundige reserves) |
| Schade (P&C) | Auto, Thuis, Professionele RC, Brand | 1 jaar (hernieuwbaar) | Eigendom, burgerlijke aansprakelijkheid | Gemiddeld (claimfrequentie, gemiddelde kosten) |
| Gezondheid (Gezondheid) | Vergoeding van kosten, ongevallen, LTC | 1 jaar / meerjarig | Morbiditeit, handicap | Hoog (ICD, DRG, codering van gezondheidsnetwerken) |
| Specialiteiten | Marine, luchtvaart, cyber, D&O, E&O | Variabel | Complexe/catastroferisico's | Zeer hoog (CAT-modellen, accumulaties) |
Implicatie voor de ontwikkelaar
Er bestaat niet één ‘one-size-fits-all’ datamodel voor verzekeringen. Een Life-systeem beheert wiskundige reserves en sterftetafels; een P&C-systeem beheert eigen risico, limieten en taxaties; een gezondheidszorgsysteem beheert medische codes en netwerken van aanbieders. De architectonische keuze tussen een uniform model e gespecialiseerde modellen voor LOB (Line of Business) is een van de meest cruciale beslissingen bij het ontwerpen van een verzekeringsplatform.
De actoren van de waardeketen
Het verzekeringsecosysteem omvat talrijke actoren met verschillende rollen. Elk van hen wordt een entiteit in ons datamodel en vaak een afzonderlijk begrensde context in de architectuur.
Kaart van de belangrijkste acteurs
| Acteur | Rol in het domein | Sleutelgegevensentiteit | Belangrijkste interacties |
|---|---|---|---|
| Contractant (verzekeringnemer) | Koop de polis, betaal de premies | Klant, Account, Betaalmethode | Quota, binden, premie betalen, claim indienen |
| Verzekerd | Persoon/ding die onder de polis valt | Verzekerde Partij, RiskObject | Kan verschillen per opdrachtnemer |
| Verzekeraar (Verzekeraar / Vervoerder) | Neemt het risico, betaalt de claims | Bedrijf, Portefeuille, Reserve | Claims onderschrijven, uitgeven en afwikkelen |
| Tussenpersoon | Vertegenwoordigt de verzekeraar, verkoopt polissen | Agent, Agentschap, Commissie | Gedistribueerd, quota, service |
| Makelaar | Vertegenwoordigt de klant, onderhandelt over voorwaarden | Makelaar, makelaarskantoor, plaatsing | Plaats risico's, onderhandel over voorwaarden |
| Herverzekeraar | Verzekert de verzekeraar (eigen risico’s) | Verdrag, toewijzing, herstel | Opbrengsten, retraites, afwikkeling |
| Deskundige (regelaar) | Evalueert claims en bepaalt de schadevergoeding | Beoordeling, schatting, rapport | Inspecteren, beoordelen, aanbevelen |
| Regelaar (regelaar) | Houdt toezicht op de markt, legt regels op | Indiening, compliance, rapporten | Producten goedkeuren, auditeren, voltooien |
Kritieke relatie: contractant versus verzekerde versus begunstigde
Een van de meest onderschatte complexiteiten is de onderscheid tussen verzekeringnemer, verzekerde en begunstigde. In het eenvoudigste geval (individueel autobeleid) vallen de drie cijfers samen. Maar bij een zakelijke levensverzekeringspolis is de aannemer en het bedrijf, de verzekerd zijn de medewerkers, en de begunstigden zij zijn de aangewezen familieleden. Het datamodel moet Ondersteun deze flexibiliteit met veel-op-veel-relaties tussen deze entiteiten.
De verzekeringswaardeketen
De verzekeringswaardeketen beschrijft de gehele bedrijfsstroom vanaf het eerste contact met de verzekeringsmaatschappij klant totdat de claim is afgehandeld en de polis is verlengd. Elke schakel in de keten komt doorgaans overeen met a begrensde context op het gebied van softwarearchitectuur.
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. Distributie
Distributie omvat alle kanalen waarlangs verzekeringsproducten de klant bereiken: agenten (single-firma of multi-firma), makelaar, bankverzekering, online vergelijkers e directe kanalen (web, app, callcenter). Voor de ontwikkelaar is dit vertaalt zich in API's voor offertes via meerdere kanalen, geïntegreerde CRM's en productconfiguratie-engines.
2. Acceptatie (risico-aanname)
Acceptatie is het proces waarbij de verzekeraar het voorgestelde risico evalueert en besluit of hij het accepteert. onder welke voorwaarden en tegen welke prijs. Het is het technische hart van het verzekeringsbedrijf en omvat:
- Risicobeoordeling: Evaluatie van risicokenmerken (leeftijd, gezondheid, locatie, schadegeschiedenis)
- Beoordeling: Berekening van de premie via de beoordelingsmotor (actuariële algoritmen + bedrijfsregels)
- Risicoselectie: Beslissing om de voorwaarden te accepteren, af te wijzen of te wijzigen
- Verwijzingen: Escalatie naar senior underwriter voor risico's buiten de automatische parameters
3. Beleidsbeheer (beleidsadministratie)
Il Beleidsadministratiesysteem (PAS) is het centrale systeem dat het geheel beheert levenscyclus van de polis: uitgifte, variaties (goedkeuring), verlengingen, opzeggingen en herstel. Het is doorgaans het meest complexe systeem in het IT-ecosysteem van verzekeringen.
4. Claimbeheer
Claimmanagement omvat het gehele proces vanaf het melden van de claim (FNOL - Eerste kennisgeving van Verlies) tot liquidatie en mogelijk herstel (subrogatie). En het proces dat heeft een directe invloed op de klanttevredenheid en de winstgevendheid van verzekeraars.
5. Investeringen en reservebeheer
Verzekeraars beleggen de geïnde premies in afwachting van de betaling van toekomstige claims. Het bestuur van investeringen (Beheer van activa en passiva) en de berekening van reserves technieken het zijn gereguleerde processen die geavanceerde actuariële modellen vereisen.
Fundamentele datamodellen
Laten we tot de kern komen van wat een ontwikkelaar moet modelleren. De volgende zijn de aggregaten (in de DDD-zin) basisprincipes van elk verzekeringsplatform.
Belangrijkste entiteiten en relaties
// ============================================
// 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;
}
Sleutelpatroon: onveranderlijkheid en versiebeheer
Merk op hoe elke interface gebruikt readonly op alle eigendommen. Op verzekeringsgebied is
de traceerbaarheid en een wettelijke vereiste: elke verandering in een beleid genereert
een nieuwe aanbeveling waardoor de version. Het ‘verandert’ nooit.
een beleid; er wordt een nieuwe versie gemaakt. Dit patroon past perfect bij deevenementenbron
en met CQRS-architecturen.
De beleidslevenscyclus
Het beleid doorloopt tijdens zijn bestaan welomschreven toestanden. Laten we deze levenscyclus modelleren zoals één staatsmachine, een fundamenteel patroon in verzekeringssoftware.
// ============================================
// 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,
};
}
Belangrijke fasen van de levenscyclus
Fase vóór uitgifte
- Kansen: Indicatieve schatting op basis van minimale gegevens. Typische geldigheidsduur: 30 dagen
- Sollicitatie: Formeel voorstel met alle gegevens die nodig zijn voor de acceptatie
- Binden: De verzekeraar stemt ermee in om dekking te bieden (maar de polis is nog niet uitgegeven)
- Probleem: Uitgifte van het officiële beleidsdocument
Fase na uitgifte
- Onderschrijft: Wijziging van de geldige voorwaarden (nieuwe versie)
- Vernieuwen: Verlenging na afloop (kan een herbeoordeling met zich meebrengen)
- Opschorten: Tijdelijke opschorting (bijvoorbeeld niet-betaling)
- Annuleren: Annulering met berekening van de opbouwpremie
- Opnieuw instellen: Herplaatsing na schorsing of verbeurdverklaring
De claimlevenscyclus
Het ongeval is de gebeurtenis die de verzekeringsbelofte activeert. De levenscyclus ervan is hetzelfde gestructureerd en leent zich uitstekend voor modellering als staatsmachine.
// ============================================
// 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;
}
De fasen van het ongeval in detail
| Fase | Activiteit | Betrokken acteurs | Gegenereerde gegevens |
|---|---|---|---|
| FNOL | Meld het ongeval via telefoon, web, app, e-mail | Verzekerd, callcenter | ClaimNotificatie, InitialReserve |
| Triage | Claimclassificatie, prioriteitstoewijzing, dekkingsverificatie | Claimbehandelaar, automatisch systeem | DekkingVerificatie, Prioriteit, Toewijzing |
| Onderzoek | Verzamelen van documentatie, taxatie, verificatie van omstandigheden | Deskundige, onderzoeker, medisch onderzoeker | Beoordeling, foto's, deskundigenrapport |
| Berechting | Beslissing: totale, gedeeltelijke aanvaarding of afwijzing | Claimmanager, Claimcommissie | Beslissing, AanpassingsCalc |
| Nederzettingen | Berekening van compensatie en betaling | Schadebehandelaar, Betaalbureau | Betaling, Afrekeningsovereenkomst |
| Herstel | Subrogatie jegens verantwoordelijke derden, bergingsherstel | Juridisch kantoor, Herstelkantoor | Subrogatieclaim, herstel |
De architectuur van de ratingengine
Il beoordelingsmotor en het onderdeel dat de verzekeringspremie berekent. En een van de meest kritische en krachtige systemen in het InsurTech-ecosysteem: het moet duizenden offertes verwerken per seconde met actuariële precisie en volledige traceerbaarheid.
Hoe de premieberekening werkt
De berekening van de premie voor een pijpleiding is definitief van aard en is van belang in een pijpleiding uiteindelijke prijs. Laten we een vereenvoudigd voorbeeld bekijken voor auto-TPL.
// ============================================
// 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,
};
}
Architectuur van de moderne beoordelingsengine
Een beoordelingsengine in productie is veel complexer dan dit voorbeeld. De belangrijkste kenmerken zijn onder meer:
- Tarieftabellen versie: Elke tarieftabel heeft een ingangsdatum. Het systeem moet de juiste tabel toepassen op basis van de ingangsdatum van de polis, niet de huidige datum
- Afzonderlijke regelengine: Bedrijfsregels (limieten, uitsluitingen, kortingen) kunnen worden geconfigureerd zonder de code te implementeren, meestal via een regelsengine (gebaseerd op Drools, RETE of JSON)
- Volledig audittraject: Elke stap van de berekening moet traceerbaar zijn voor naleving van de regelgeving
- Horizontale schaalbaarheid: De beoordelingsengine moet pieken van duizenden offertes per seconde beheren (vergelijkers, open inschrijving)
- Idempotentie: Dezelfde input moet altijd dezelfde output produceren (pure functie)
Domeingestuurd ontwerp voor verzekeringen
Domain-Driven Design (DDD) is de meest geschikte architectonische aanpak voor het verzekeringsdomein de intrinsieke complexiteit ervan en de noodzaak om de software af te stemmen op de taal van het bedrijf. Laten we eens kijken hoe we het concreet kunnen toepassen.
Begrensde context van het verzekeringsecosysteem
Elke begrensde context heeft zijn eigen context alomtegenwoordige taal, zijn modellen en eigen regels. De term "polis" heeft verschillende betekenissen in de Underwriting-context (te beoordelen voorstel) vergeleken met polisadministratie (uitgegeven contract).
// ============================================
// 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
Aggregaten en invarianten
In DDD, elke totaal beschermt zijn bedrijfsinvarianten. Hier zijn ze belangrijkste invarianten voor de twee belangrijkste aggregaten:
Geaggregeerd beleid
- Een polis moet minimaal één actieve dekking hebben
- De vervaldatum moet na de ingangsdatum liggen
- De totale premie moet de som zijn van de dekkingspremies + ladingen
- Elke goedkeuring moet de versie verhogen
- Staatstransities moeten de staatsmachine respecteren
- Een polis kan niet worden opgezegd als er openstaande claims zijn
Claimaggregaat
- De datum van het ongeval moet binnen de dekkingsperiode van de polis vallen
- De reserve kan niet negatief zijn
- Het totaalbedrag dat u betaalt, mag de dekkingslimiet niet overschrijden
- Een gesloten claim kan geen nieuwe betalingen ontvangen (deze moet worden heropend)
- Het besluit vereist minimaal een deskundigenonderzoek
- De betaling vereist goedkeuring als deze de autoriteitsdrempel overschrijdt
Domeingebeurtenissen
I domeinevenementen zij zijn het mechanisme waarmee begrensde contexten op een bepaalde manier communiceren ontkoppeld. Elke gebeurtenis vertegenwoordigt iets belangrijks dat in het domein is gebeurd.
// ============================================
// 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()
ACORD-normen en interoperabiliteit
ACORD (Vereniging voor Coöperatief Onderzoek en Ontwikkeling) e de organisatie die datastandaarden vaststelt voor de wereldwijde verzekeringssector. Voor een ontwikkelaar is ACORD het equivalent van HL7/FHIR voor de gezondheidszorg of SWIFT voor de financiële wereld.
ACORD-gegevensstandaarden: wat ze zijn
ACORD biedt gedetailleerde datamodellen, berichtformaten (XML en JSON) en schema's speciaal ontworpen voor verzekeringsprocessen. Het doel is om doorstroming te garanderen efficiënte gegevensverwerking tussen alle spelers in het ecosysteem: verzekeraars, makelaars, agenten, herverzekeraars en toezichthouders.
| Standaard ACORD | Formaat | Gebruik | Sector |
|---|---|---|---|
| ACORD AL3 | Eigenaar (vaste lengte) | Gegevensuitwisseling agent-verzekeraar (VS) | P&C persoonlijke lijnen |
| ACORD-XML | XML-schema | Offerte, uitgifte, claims, facturering | P&C, Leven, Gezondheid |
| ACORD GRLC 2.0 | JSON/XML | Herverzekering en grote commerciële (wereldwijd) | Herverzekering, specialiteit |
| ACORD Volgende generatie | JSON (API-eerst) | Microservices, REST API, asynchrone gebeurtenissen | Sectoroverschrijdend |
| ACORD-formulieren | PDF/XML | Gestandaardiseerde formulieren (certificaten, bijlagen) | P&C (VS) |
GRLC Generatie 2.0 (april 2025)
De belangrijkste update van de afgelopen jaren en de lancering van GRLC-generatie 2.0, een digital-first, op JSON gebaseerde standaard die is geoptimaliseerd voor fijnmazige transacties zoals microservices en API's. Het ondersteunt end-to-end straight-through-verwerking van de gehele beleidslevenscyclus in het mondiale herverzekeringsecosysteem, waardoor moderne integraties mogelijk worden gemaakt zonder dat er oude integraties nodig zijn Batch XML-formaten.
API-patroon voor verzekeringen
Moderne verzekerings-API's volgen specifieke patronen die de complexiteit van het domein weerspiegelen:
- Asynchroon citeren: Complexe offertes (commercieel, gespecialiseerd) vereisen asynchrone verwerking. De API retourneert een
quoteRequestIden na voltooiing via webhook op de hoogte stellen - Tijdelijk versiebeheer: Elke hulpbron (beleid, dekking) heeft een tijdsdimensie. De API ondersteunt query's voor
asOfDateom de historische toestand te herstellen - Idempotentie: De bind- en betalingstransacties moeten via idempotent plaatsvinden
idempotencyKeyom duplicatie te voorkomen - Evenementstreaming: Statuswijzigingen worden gemeld via gebeurtenissen (webhook of message broker) voor integratie met downstream-systemen
Het regelgevingslandschap
De verzekeringssector is een van de meest gereguleerde ter wereld. Voor een ontwikkelaar betekent dit wat veel architectonische beslissingen zijn gedicteerd door naleving, niet alleen van beste praktijken op het gebied van techniek.
Belangrijke regelgeving en impact op software
| Verordening | Domein | Impact op software |
|---|---|---|
| Solvabiliteit II | EU - Kapitaal- en solvabiliteitsvereisten | Risicomodellen, SCR-berekening (Solvency Capital Requirement), XBRL-rapportage, datakwaliteitsraamwerk |
| IFRS 17 | Globaal - Boekhouding van verzekeringscontracten | CSM-berekening (Contractual Service Margin), contractgroepering, meetmodellen (BBA, VFA, PAA) |
| AVG / Privacy | EU - Bescherming van persoonlijke gegevens | Gedetailleerde toestemming, recht om vergeten te worden versus verplichte bewaring (conflict), pseudonimisering, DPIA |
| IDD | EU - Verzekeringsdistributie | Traceerbaarheid van consultancy, geschiktheid van producten, belangenconflicten, precontractuele documentatie |
| DORA | EU - Digitale operationele veerkracht | ICT-risicobeheer, incidentrapportage, testen van veerkracht, risico van derden (cloudprovider) |
| ICS 2025 | Wereldwijd - Kapitaalstandaard voor IAIG | Wettelijke kapitaalberekening met uniforme mondiale standaard (operationeel vanaf 2025) |
Het GDPR versus het verzekeringsretentieconflict
Eén van de meest complexe dilemma’s voor de verzekeringsontwikkelaar: de AVG legt de juist tot vergetelheid, maar de verzekeringsregelgeving vereist de gegevensretentie voor perioden variërend van 5 tot 30 jaar (vorderingen met openstaande reserves, juridische geschillen, verplichtingen actuarieel). De typische oplossing houdt in progressieve pseudonimisering: de gegevens ID's worden gescheiden van transactiegegevens en indien mogelijk verwijderd, waarbij ze behouden blijven geanonimiseerde gegevens voor wettelijke verplichtingen.
Architectuur van een modern InsurTech-platform
Moderne verzekeringsplatforms hanteren een architectuur cloud-native, API-eerst, gebeurtenisgedreven. De oude monoliet wordt opgesplitst in begrensde microservices domeincontext.
Typische technologiestapel (2025-2026)
| Lagen | Technologieën | Functie |
|---|---|---|
| Frontend | Hoekig, React, Vue + micro-frontend | Agentenportaal, klantenportaal, backoffice |
| API-gateway | Kong, AWS API-gateway, Apigee | Snelheidsbeperking, authenticatie, routering, versiebeheer |
| Microdiensten | Node.js/NestJS, Java/Spring Boot, Go | Beleid, claims, beoordeling, facturering, CRM |
| Evenementenbus | Apache Kafka, AWS EventBridge, RabbitMQ | Domeinevenementen, CQRS, evenementensourcing |
| Databases | PostgreSQL, MongoDB, DynamoDB | Database per service (database per begrensde context) |
| AI/ML | Python, TensorFlow, SageMaker | Fraudedetectie, prijsoptimalisatie, OCR-documenten |
| Orkestratie | Kubernetes, AWS ECS, Temporal.io | Schaalvergroting, sagapatronen, langlopende workflows |
| Waarneembaarheid | Datadog, Grafana, OpenTelemetrie | Gedistribueerde tracering, statistieken, gecentraliseerde logboekregistratie |
Belangrijke architecturale patronen
Eventsourcing voor beleid
L'evenementenbron Een deel van de hulp aan de Dominie is van toepassing beleid en intrinsiek een opeenvolging van gebeurtenissen (uitgifte, goedkeuring, verlenging, claim). In plaats van alleen de huidige status op te slaan, slaat u alle gebeurtenissen op en bouwt u deze opnieuw op de huidige status via opnieuw afspelen. Dit levert automatisch een volledig audittraject op, een belangrijke wettelijke vereiste.
Saga-patroon voor cross-contextprocessen
Processen zoals het afgeven van een polis omvatten meerdere begrensde contexten: acceptatie keurt goed, Problemen met polisbeheer, Facturering maakt de factuur, Herverzekering berekent de toewijzing. De saga-patroon (georkestreerd of gechoreografeerd) coördineert deze gedistribueerde stappen het garanderen van uiteindelijke consistentie en compensatie in geval van mislukking. Tijdelijk.io e vooral populair bij InsurTech voor het implementeren van langlopende stateful workflows volhardend.
Multi-agent AI-systemen (Trend 2026)
In plaats van één enkele monolithische AI-assistent staan de meest geavanceerde InsurTech-platforms implementeren systemen met meerdere agenten met gespecialiseerde agenten: één agent voor de inname van declaraties, één voor de fraudecheck, één voor de communicatie naar de klant, één voor betalingen en terugvordering. Deze agenten worden georkestreerd via duidelijke workflows en ze werken samen om de gehele levenscyclus van claims te automatiseren.
Conclusies en volgende stappen
Het verzekeringsdomein is een van de rijkste en meest complexe waarmee een ontwikkelaar te maken kan krijgen. In dit artikel hebben we de fundamenten gelegd: de producten, de actoren, de waardeketen, de datamodellen, levenscycli, de ratingengine, de toegepaste DDD en het regelgevingslandschap.
Hier zijn de afhaalrestaurants voornaamst:
- Het verzekeringsproduct is een belofte: dit maakt datamodellen inherent temporeel en voorzien van versiebeheer
- Er bestaat geen universeel model: Leven, P&C, Gezondheid en Specialiteit hebben totaal verschillende behoeften
- De staatsmachine en het fundamentele patroon: voor zowel polissen als claims: de levenscyclus en een staatsmachine met duidelijk gedefinieerde transities
- Onveranderlijkheid is een wettelijke vereiste: elke wijziging genereert een nieuwe versie, nooit een overschrijving
- DDD en de natuurlijke aanpak: begrensde context afgestemd op de waardeketen, aggregaten die bedrijfsinvarianten beschermen, domeingebeurtenissen voor ontkoppeling
- Compliance bepaalt de architectuur: Solvency II, IFRS 17, GDPR en DORA zijn geen ‘nice to haves’ maar primaire architecturale beperkingen
- ACORD en de lingua franca: ACORD-standaarden (vooral Next-Gen JSON) zijn essentieel voor interoperabiliteit in het ecosysteem
In de volgende aflevering
In het volgende artikel van de InsurTech Engineering-serie gaan we dieper in op de Beleid Administratiesysteem: hoe ontwerp je een moderne PAS met productconfigurator, temporeel versiebeheer, goedkeuringsengine en integratie met de beoordelingsengine. We zullen zien concrete patronen om de complexiteit van verzekeringsproducten met meerdere dekkingen te beheren een domeingedreven aanpak.







