개발자를 위한 보험 영역: 제품, 행위자 및 데이터 모델
당신이 보험계에 처음 입문한 소프트웨어 개발자라면 아마도 당신은 이해할 수 없는 전문 용어에 직면하게 될 것입니다: 인수, 배서, FNOL, 대위, 국경. 걱정하지 마세요. 이 가이드는 전체 도메인을 번역합니다. 개발자가 이해할 수 있는 개념, 데이터 모델 및 아키텍처 패턴에 보험을 추가하고, 구현하고 무엇보다 올바르게 모델링하다 코드에서.
보험산업은 전 세계적으로 발전하고 있습니다. 연간 보험료 7조 달러 (데이터 2025, Swiss Re Sigma) 세계에서 가장 규제가 심한 부문 중 하나입니다. 그러나 대부분의 이를 지원하는 정보 시스템은 80년대와 90년대로 거슬러 올라갑니다: COBOL 메인프레임, 야간 배치, 그린 스크린 인터페이스. 산업계의 디지털 전환이라고 불리는 인슈어테크, 는 이 모든 것을 재설계하고 있으며, 그 변화의 중심에는 개발자가 있습니다.
이 기사는 시리즈를 시작합니다 인슈어테크엔지니어링 전체 개요와 함께 해당 영역: 보험 상품, 가치 사슬 플레이어, 기본 데이터 모델, 정책 및 청구 수명 주기, 플랫폼 구축을 위한 최신 아키텍처 패턴 클라우드 네이티브 보험.
이 기사에서 배울 내용
- 보험 상품 카테고리(생명, 손해, 건강, 전문) 및 기술적 차이점
- 가치 사슬의 참여자: 보험 계약자, 보험사, 중개인, 대리인, 재보험사, 규제 기관
- 보험 가치 사슬: 유통, 인수, 정책 관리, 청구, 투자
- 기본 데이터 모델: 정책, 청구, 프리미엄, 보장, 보증, 특약
- 보험증권의 전체 라이프사이클: 견적, 발행, 변경, 갱신, 취소
- 청구의 수명주기: FNOL, 평가, 해결, 복구
- 보험에 적용되는 도메인 중심 설계: 제한된 컨텍스트 및 집계
- 등급 엔진의 아키텍처와 보험료 계산
- 상호 운용성을 위한 ACORD 표준 및 API 패턴
- 규제 환경: Solvency II, IFRS 17, GDPR
보험 산업: 개발자 개요
한 줄의 코드를 작성하기 전에 다음 사항을 이해하는 것이 중요합니다. 사업이 어떻게 돌아가는지 보험. 상품이 눈에 보이는 전자상거래와 달리 보험에서는 "제품"은 약속하다: 사고 발생 시 향후 보상금 지급 불확실한 사건. 이는 데이터 모델링 관점에서 도메인을 본질적으로 복잡하게 만듭니다.
"보험은 결코 사용하지 않기를 바라면서 사는 유일한 상품입니다. 이 역설은 이를 관리하는 시스템의 전체 아키텍처를 정의합니다."
기본 원칙: 위험의 상호성
핵심 컨셉은 위험 상호성 (위험 풀링): 좋은 것 같아요 개인 또는 회사 그룹이 공동 기금에 정기적으로 보험료를 기부하고 그로부터 인출됩니다. 피해를 입은 소수를 보상하기 위한 자원. 보험사의 역할과 이를 관리하는 역할 징수된 보험료가 보험금을 충당하기에 충분하도록 보험계리적으로 지속 가능한 방식으로 자금을 조달합니다. 예상 청구액에 운영 비용 및 이윤을 더한 금액입니다.
보험 상품 카테고리
보험 상품은 근본적으로 다른 기술적 특성을 지닌 거시적 카테고리로 구분됩니다. 데이터를 올바르게 모델링하려면 이러한 차이점을 이해하는 것이 중요합니다.
| 범주 | Esempi | 일반적인 기간 | 위험의 성격 | 데이터 복잡성 |
|---|---|---|---|---|
| 생활 (생활) | 기간, 혼합, 단위 연결, 보드 | 10~40년 | 사망, 장수 | 높음(보험 통계 테이블, 수학 준비금) |
| 손해(손해배상) | 자동차, 집, 전문가용 RC, 화재 | 1년(갱신 가능) | 재산, 민사책임 | 평균(청구 빈도, 평균 비용) |
| 건강 (건강) | 비용, 사고, LTC 상환 | 1년/다년 | 질병, 장애 | 높음(ICD, DRG, 의료 네트워크 코딩) |
| 특산품 | 해양, 항공, 사이버, D&O, E&O | 변하기 쉬운 | 복합/재난 위험 | 매우 높음(CAT 모델, 누적) |
개발자를 위한 시사점
보험에는 "모든 경우에 적용되는 단일" 데이터 모델이 없습니다. 라이프 시스템이 관리합니다. 수학 준비금 및 사망률 테이블; P&C 시스템은 공제액, 한도 및 평가; 의료 시스템은 의료 코드와 의료 제공자 네트워크를 관리합니다. 건축학적 선택 사이 통합 모델 e LOB를 위한 특화된 모델 (사업 부문)은 보험 플랫폼 설계에 있어 가장 중요한 결정 중 하나입니다.
가치 사슬의 행위자
보험 생태계에는 서로 다른 역할을 맡은 수많은 행위자가 참여합니다. 그들 각각은 데이터 모델의 엔터티이며 종종 아키텍처의 별도의 제한된 컨텍스트입니다.
주요 배우 지도
| 배우 | 도메인에서의 역할 | 주요 데이터 엔터티 | 주요 상호작용 |
|---|---|---|---|
| 계약자(보험 계약자) | 보험을 구매하고 보험료를 지불하세요 | 고객, 계좌, 결제수단 | 할당량, 바인딩, 프리미엄 지불, 청구 제기 |
| 보험 | 보험이 적용되는 사람/사물 | 피보험자, RiskObject | 시공사와 다를 수 있음 |
| 보험사(보험사/보험사) | 위험을 감수하고 청구 금액을 지불합니다. | 회사, 포트폴리오, 예비비 | 보험금 인수, 발행, 해결 |
| 대리인 | 보험사를 대표하고 보험 상품을 판매합니다. | 대리인, 대행사, 수수료 | 분산, 할당량, 서비스 |
| 브로커 | 고객을 대표하고 조건을 협상합니다. | 브로커, 브로커펌, 배치 | 위험을 감수하고 조건을 협상하세요 |
| 재보험사 | 보험사에 보험을 보장합니다(초과 위험). | 조약, 양도, 회수 | 수확량, 후퇴, 정착 |
| 전문가(조정자) | 청구를 평가하고 보상 결정 | 평가, 추정, 보고 | 검사, 평가, 추천 |
| 레귤레이터(레귤레이터) | 시장을 감독하고 규칙을 부과합니다. | 제출, 규정 준수, 보고서 | 제품 승인, 감사, 완료 |
중요한 관계: 계약자, 피보험자, 수혜자
가장 과소평가된 복잡성 중 하나는 보험계약자, 피보험자, 피보험자의 구별 수혜자. 가장 간단한 경우(개별 자동차 정책)에서는 세 수치가 일치합니다. 하지만 기업생명보험에서는 계약자 그리고 회사, 그 보험 직원이고, 수혜자 그들은 지정된 가족 구성원입니다. 데이터 모델은 다음과 같아야 합니다. 이러한 엔터티 간의 다대다 관계를 통해 이러한 유연성을 지원합니다.
보험 가치 사슬
보험 가치사슬은 고객과의 첫 접촉부터 비즈니스의 전체 흐름을 설명합니다. 청구가 해결되고 정책이 갱신될 때까지 고객. 체인의 모든 링크 일반적으로 다음과 같습니다. 제한된 컨텍스트 소프트웨어 아키텍처에서.
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. 배포
유통에는 보험 상품이 고객에게 도달하는 모든 채널이 포함됩니다. 자치령 대표 (단일 회사 또는 다중 회사), 브로커, 방카슈랑스, 온라인 비교기 e 직접 채널 (웹, 앱, 콜센터). 개발자의 경우, 이는 다중 채널 견적 API, 통합 CRM 및 제품 구성 엔진으로 변환됩니다.
2. 인수(위험 가정)
언더라이팅은 보험사가 제안된 위험을 평가하고 이를 수락할지 여부를 결정하는 프로세스입니다. 어떤 조건에서, 어떤 가격으로. 이는 보험 사업의 기술적 핵심이며 다음을 포함합니다.
- 위험 평가: 위험 특성 평가(연령, 건강, 위치, 청구 내역)
- 평가: 보험료 계산은 다음을 통해 이루어집니다. 평가 엔진 (계리 알고리즘 + 비즈니스 규칙)
- 위험 선택: 조건을 수락, 거부 또는 수정하기로 결정
- 추천: 자동 매개변수를 벗어난 위험에 대해서는 선임 보험사에게 에스컬레이션
3. 정책관리(정책관리)
Il 정책행정시스템 (PAS)는 전체를 관리하는 중앙 시스템입니다. 정책의 수명 주기: 발행, 변경(승인), 갱신, 취소 및 복직. 일반적으로 보험 IT 생태계에서 가장 복잡한 시스템입니다.
4. 청구 관리
클레임관리는 클레임 접수부터 클레임 접수까지 전 과정을 총괄합니다(FNOL - 첫 번째 통지 손실) 청산 및 회수(대위권)가 가능할 때까지. 그리고 그 과정은 고객 만족도와 보험사 수익성에 직접적인 영향을 미칩니다.
5. 투자 및 적립금 관리
보험사는 미래의 보험금 지급을 예상하여 징수한 보험료를 투자합니다. 관리 투자 (자산-부채 관리) 및 계산 준비금 기술 이는 정교한 계리 모델이 필요한 규제된 프로세스입니다.
기본 데이터 모델
개발자가 모델링해야 하는 내용의 핵심을 살펴보겠습니다. 다음은 집합체 (DDD 의미에서) 모든 보험 플랫폼의 기본입니다.
주요 엔터티 및 관계
// ============================================
// 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;
}
주요 패턴: 불변성과 버전 관리
각 인터페이스가 어떻게 사용되는지 확인하세요. readonly 모든 속성에 대해. 보험 분야에서는
는 추적성 규제 요구사항: 정책이 변경될 때마다
새로운 것 배서 이는 version. 결코 "변화"하지 않습니다.
정책; 새 버전이 생성됩니다. 이 패턴은 와 완벽하게 어울려요이벤트 소싱
그리고 CQRS 아키텍처를 사용합니다.
정책 수명주기
정책은 존재하는 동안 잘 정의된 상태를 거칩니다. 이 수명주기를 모델링해 봅시다. 하나처럼 상태 머신, 보험 소프트웨어의 기본 패턴입니다.
// ============================================
// 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,
};
}
수명주기의 주요 단계
사전 발행 단계
- 승산: 최소 데이터를 기반으로 한 추정치입니다. 일반적인 유효 기간: 30일
- 애플리케이션: 인수에 필요한 모든 데이터가 포함된 공식 제안서
- 묶다: 보험사가 보험 보장을 제공하는 데 동의합니다(그러나 보험 증권은 아직 발행되지 않음).
- 문제: 공식 정책 문서 발행
발급 후 단계
- 지지합니다: 유효한 조건 수정(새 버전)
- 고쳐 쓰다: 만료 시 갱신(재평가가 포함될 수 있음)
- 유예하다: 일시 정지(예: 미납)
- 취소: 발생 보험료 계산으로 취소
- 다시 놓기: 정지 또는 몰수 후 복직
청구 수명 주기
사고는 보험약속을 활성화하는 사건이다. 수명주기는 동일합니다. 구조화되어 있으며 상태 머신으로 모델링하는 데 완벽하게 적합합니다.
// ============================================
// 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;
}
사고의 세부 단계
| 단계 | 활동 | 관련된 배우 | 생성된 데이터 |
|---|---|---|---|
| FNOL | 전화, 웹, 앱, 이메일을 통해 사고신고 | 보험, 콜센터 | 청구 알림, 초기 예약 |
| 분류 | 청구분류, 우선순위 부여, 보장범위 확인 | 클레임 처리자, 자동 시스템 | Coverage검증, 우선순위, 할당 |
| 조사 | 서류수집, 감정, 상황확인 | 전문가, 수사관, 검시관 | 평가, 사진, 전문가 보고서 |
| 판결 | 결정: 전체, 부분 승인 또는 거부 | 청구 관리자, 청구 위원회 | 결정, 조정Calc |
| 정착지 | 보상 및 지불 계산 | 청구 처리자, 지불 사무국 | 결제, 정산합의 |
| 회복 | 책임 있는 제3자에 대한 대위, 구난회수 | 법률사무소, 복구사무소 | 대위청구, 회수 |
평가 엔진의 아키텍처
Il 평가 엔진 보험료를 계산하는 구성요소입니다. 그리고 그 중 하나는 InsurTech 생태계에서 가장 중요한 고성능 시스템: 수천 건의 견적을 처리해야 합니다. 정확한 통계와 완벽한 추적성을 바탕으로 초당 처리됩니다.
프리미엄 계산 작동 방식
보험료 계산은 위험 요소를 다음으로 변환하는 잘 정의된 파이프라인을 따릅니다. 최종 가격. Car 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,
};
}
최신 평가 엔진의 아키텍처
프로덕션 환경의 평가 엔진은 이 예보다 훨씬 더 복잡합니다. 주요 기능은 다음과 같습니다:
- 버전이 지정된 요율표: 각 관세표에는 발효일이 있습니다. 시스템은 현재 날짜가 아닌 정책 시행일을 기준으로 올바른 테이블을 적용해야 합니다.
- 별도의 규칙 엔진: 일반적으로 규칙 엔진(Drools, RETE 또는 JSON 기반)을 통해 코드를 배포하지 않고도 비즈니스 규칙(한도, 제외, 할인)을 구성할 수 있습니다.
- 전체 감사 추적: 계산의 각 단계는 규정 준수를 위해 추적 가능해야 합니다.
- 수평적 확장성: 평가 엔진은 초당 수천 개의 견적 최고치를 관리해야 합니다(비교자, 공개 등록).
- 멱등성: 동일한 입력은 항상 동일한 출력을 생성해야 합니다(순수 기능).
보험을 위한 도메인 중심 설계
DDD(Domain-Driven Design)는 보험 도메인에 가장 적합한 아키텍처 접근 방식입니다. 본질적인 복잡성과 소프트웨어를 비즈니스 언어에 맞춰 조정해야 할 필요성. 구체적으로 어떻게 적용하는지 살펴보겠습니다.
보험 생태계의 제한된 컨텍스트
각 경계 컨텍스트에는 고유한 컨텍스트가 있습니다. 유비쿼터스 언어, 그 모델 및 자신의 규칙. "정책"이라는 용어는 Underwriting 맥락에서 다른 의미를 갖습니다. (평가할 제안)과 정책행정(계약서 발행) 비교.
// ============================================
// 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
집계 및 불변
DDD에서는 모든 골재 비즈니스 불변성을 보호합니다. 여기 있습니다 두 개의 키 집계에 대한 주요 불변성:
집계 정책
- 정책에는 하나 이상의 활성 적용 범위가 있어야 합니다.
- 만료일은 발효일 이후여야 합니다.
- 총 보험료는 보장 보험료 + 부담금의 합이어야 합니다.
- 각 보증은 버전을 높여야 합니다.
- 상태 전환은 상태 시스템을 존중해야 합니다.
- 공개 소유권 주장으로는 정책을 취소할 수 없습니다.
청구 집계
- 사고 발생일이 보험 보장 기간 내에 속해야 합니다.
- 준비금은 음수일 수 없습니다.
- 지불된 총액은 보장 한도를 초과할 수 없습니다.
- 종결된 청구는 새로운 지급을 받을 수 없습니다(재개설되어야 함).
- 결정에는 최소한 전문가 평가가 필요합니다.
- 권한 한도를 초과하는 경우 결제 승인이 필요합니다.
도메인 이벤트
I 도메인 이벤트 제한된 컨텍스트가 어떤 방식으로 통신하는 메커니즘입니다. 분리됨. 각 이벤트는 해당 도메인에서 발생한 중요한 일을 나타냅니다.
// ============================================
// 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 표준 및 상호 운용성
어코드 (협력운영연구개발협회) e 글로벌 보험 산업의 데이터 표준을 설정하는 조직입니다. 개발자의 경우 ACORD는 의료용 HL7/FHIR, 금융용 SWIFT와 동일합니다.
ACORD 데이터 표준: 정의
ACORD는 세분화된 데이터 모델, 메시지 형식(XML 및 JSON) 및 스키마를 제공합니다. 보험 프로세스를 위해 특별히 설계되었습니다. 목표는 흐름을 보장하는 것입니다. 보험사, 중개인, 대리인 등 생태계의 모든 플레이어 간의 효율적인 데이터 처리 재보험사 및 규제 기관.
| 스탠다드 어코드 | 체재 | 용법 | 부문 |
|---|---|---|---|
| 어코드 AL3 | 소유자(고정 길이) | 대리인-보험사 데이터 교환(미국) | P&C 개인 회선 |
| ACORD XML | XML 스키마 | 견적, 발행, 청구, 청구 | 손해보험, 생명, 건강 |
| 어코드 GRLC 2.0 | JSON/XML | 재보험 및 대형 상업(글로벌) | 재보험, 전문 분야 |
| ACORD 차세대 | JSON(API 우선) | 마이크로서비스, REST API, 비동기 이벤트 | 부문간 |
| ACORD 양식 | PDF/XML | 표준화된 양식(인증서, 부록) | 피앤씨(미국) |
GRLC 2.0세대(2025년 4월)
최근 몇 년간 가장 중요한 업데이트와 출시 GRLC 세대 2.0, 마이크로서비스와 같은 세분화된 트랜잭션에 최적화된 디지털 우선 JSON 기반 표준 그리고 API. 전체 정책 수명주기의 엔드 투 엔드 직접 처리를 지원합니다. 글로벌 재보험 생태계에서 오래된 통합을 거치지 않고 현대적인 통합을 가능하게 합니다. 일괄 XML 형식.
보험용 API 패턴
최신 보험 API는 도메인 복잡성을 반영하는 특정 패턴을 따릅니다.
- 비동기식 인용: 복잡한 견적(상업용, 전문용)에는 비동기 처리가 필요합니다. API는
quoteRequestId완료되면 웹훅을 통해 알림 - 임시 버전 관리: 각 리소스(정책, 적용 범위)에는 시간 차원이 있습니다. API는 다음에 대한 쿼리를 지원합니다.
asOfDate역사적 상태를 회복하기 위해 - 멱등성: 바인드 및 결제 작업은 멱등성을 통해 이루어져야 합니다.
idempotencyKey중복을 피하기 위해 - 이벤트 스트리밍: 다운스트림 시스템과의 통합을 위해 이벤트(웹훅 또는 메시지 브로커)를 통해 상태 변경 사항이 통보됩니다.
규제 환경
보험 산업은 세계에서 가장 규제가 심한 산업 중 하나입니다. 개발자에게 이는 다음을 의미합니다. 많은 아키텍처 결정은 규정 준수에 따라 결정됨, 뿐만 아니라 엔지니어링 모범 사례.
소프트웨어에 대한 주요 규정 및 영향
| 규제 | 범위 | 소프트웨어에 미치는 영향 |
|---|---|---|
| 솔벤시 II | EU - 자본 및 지급여력 요건 | 리스크 모델, SCR(Solvency Capital Requirement) 계산, XBRL 보고, 데이터 품질 프레임워크 |
| IFRS 17 | 글로벌 - 보험 계약 회계 | CSM(계약 서비스 마진) 계산, 계약 그룹화, 측정 모델(BBA, VFA, PAA) |
| GDPR / 개인정보 보호 | EU - 개인 데이터 보호 | 세부적인 동의, 잊혀질 권리와 의무적 보존(충돌), 가명화, DPIA |
| IDD | EU - 보험 분배 | 컨설팅 추적성, 제품 적합성, 이해 상충, 계약 전 문서 |
| 도라 | EU - 디지털 운영 탄력성 | ICT 위험 관리, 사고 보고, 탄력성 테스트, 제3자 위험(클라우드 공급자) |
| ICS 2025 | 글로벌 - IAIG의 자본 표준 | 통일된 글로벌 표준에 따른 규제 자본 계산(2025년부터 운영) |
GDPR과 보험 유지 충돌
보험 개발자에게 가장 복잡한 딜레마 중 하나는 GDPR이 부과하는 것입니다. 맞아 망각에, 그러나 보험 규정에서는 다음 사항을 요구합니다. 데이터 보존 5~30년 범위의 기간(미결 준비금이 있는 청구, 법적 분쟁, 의무) 보험계리). 일반적인 솔루션에는 다음이 포함됩니다. 점진적인 가명화: 데이터 식별자는 거래 데이터와 분리되어 가능한 경우 삭제되어 유지됩니다. 규제 의무를 위해 익명화된 데이터.
최신 InsurTech 플랫폼의 아키텍처
최신 보험 플랫폼은 아키텍처를 채택합니다. 클라우드 네이티브, API 우선, 이벤트 중심. 레거시 모놀리스는 경계 정렬된 마이크로서비스로 분류됩니다. 도메인 컨텍스트.
일반적인 기술 스택(2025-2026)
| 레이어 | 기술 | 기능 |
|---|---|---|
| 프런트엔드 | Angular, React, Vue + 마이크로 프론트엔드 | 에이전트 포털, 고객 포털, 백오피스 |
| API 게이트웨이 | 홍콩, AWS API 게이트웨이, Apigee | 속도 제한, 인증, 라우팅, 버전 관리 |
| 마이크로서비스 | Node.js/NestJS, Java/Spring Boot, Go | 정책, 청구, 평가, 청구, CRM |
| 이벤트 버스 | 아파치 카프카, AWS EventBridge, RabbitMQ | 도메인 이벤트, CQRS, 이벤트 소싱 |
| 데이터베이스 | PostgreSQL, 몽고DB, 다이나모DB | 서비스당 데이터베이스(제한된 컨텍스트당 데이터베이스) |
| AI/ML | Python, TensorFlow, SageMaker | 사기 탐지, 가격 최적화, OCR 문서 |
| 관현악법 | 쿠버네티스, AWS ECS, Temporal.io | 확장, 사가 패턴, 장기 실행 워크플로 |
| 관찰 가능성 | Datadog, Grafana, OpenTelemetry | 분산 추적, 지표, 중앙 집중식 로깅 |
주요 아키텍처 패턴
정책에 대한 이벤트 소싱
L'이벤트 소싱 특히 보험 분야에 적합합니다. 정책 및 본질적으로 일련의 이벤트(발행, 승인, 갱신, 청구)입니다. 현재 상태만 저장하는 것이 아니라 모든 이벤트를 저장하고 다시 빌드합니다. 현재 상태를 통해 다시 하다. 이는 자동으로 완전한 감사 추적을 제공합니다. 주요 규제 요구사항입니다.
크로스컨텍스트 프로세스를 위한 Saga 패턴
정책 발행과 같은 프로세스에는 여러 개의 제한된 컨텍스트가 포함됩니다. 정책 관리 문제, 청구가 송장을 생성하고 재보험이 할당을 계산합니다. 그만큼 사가 패턴 (조정 또는 안무) 이러한 분산 단계를 조정합니다. 실패 시 최종 일관성과 보상을 보장합니다. Temporal.io e 장기 실행 상태 저장 워크플로우 구현을 위해 InsurTech에서 특히 인기가 있음 끈질긴.
다중 에이전트 AI 시스템(트렌드 2026)
단일한 모놀리식 AI 보조자 대신 가장 발전된 InsurTech 플랫폼이 자리잡고 있습니다. 구현 다중 에이전트 시스템 전문 에이전트와 함께: 하나의 에이전트 클레임 접수, 하나는 사기 확인용, 하나는 고객과의 커뮤니케이션용, 하나는 지불 및 복구. 이러한 에이전트는 명확한 워크플로를 통해 조정되며 그들은 전체 청구 수명주기를 자동화하기 위해 협력합니다.
결론 및 다음 단계
보험 분야는 개발자가 직면할 수 있는 가장 풍부하고 복잡한 분야 중 하나입니다. 이 기사에서 우리는 제품, 행위자, 가치 사슬 등의 기반을 구축했습니다. 데이터 모델, 수명주기, 등급 엔진, 적용된 DDD 및 규제 환경.
다음은 테이크아웃 기본:
- 보험상품은 약속입니다. 이로 인해 데이터 모델이 본질적으로 임시적이고 버전이 관리됩니다.
- 보편적인 모델은 없습니다: 생명보험, 손해보험, 의료 및 전문 분야는 근본적으로 다른 요구사항을 가지고 있습니다.
- 상태 머신과 기본 패턴: 정책과 청구 모두에 대해 수명 주기와 전환이 잘 정의된 상태 머신
- 불변성은 규제 요구 사항입니다. 모든 수정은 새 버전을 생성하며 절대 덮어쓰지 않습니다.
- DDD 및 자연스러운 접근 방식: 가치 사슬에 맞춰진 제한된 컨텍스트, 비즈니스 불변성을 보호하는 집계, 분리를 위한 도메인 이벤트
- 규정 준수가 아키텍처를 주도합니다. Solvency II, IFRS 17, GDPR 및 DORA는 "있으면 좋은" 것이 아니라 기본 아키텍처 제약 사항입니다.
- ACORD 및 링구아 프랑카: ACORD 표준(특히 차세대 JSON)은 생태계의 상호 운용성을 위해 필수적입니다.
다음 에피소드에서는
InsurTech Engineering 시리즈의 다음 기사에서는 정책 행정시스템: 제품 구성기를 사용하여 최신 PAS를 설계하는 방법, 임시 버전 관리, 보증 엔진 및 등급 엔진과의 통합. 우리는 보자 다중 보장 보험 상품의 복잡성을 관리하기 위한 구체적인 패턴 도메인 중심 접근 방식.







