Skip to content

Enrollment

Manages the full quote-to-policy lifecycle — quoting, underwriting, binding, and all in-force policy transactions.

Overview

The Enrollment service is the policy factory for Olly. It handles the end-to-end journey from a rating quote through underwriting, binding, and ongoing policy management (endorsements, renewals, cancellations, reinstatements). It integrates with Policy Admin to fetch product configuration and rule sets, and uses the shared rule engine library to enforce underwriting eligibility rules at each pricing and underwriting step.

A Quote captures the member's plan selection and application data. Once underwritten and issued, it becomes a Policy with one or more PolicyTerm records (coverage periods) and PolicyElement items (individual coverages or riders). All in-force changes — cancellations, endorsements, renewals — create PolicyTransaction records that describe the delta applied to the policy. Field values for configurable product attributes are stored in separate *FieldValue tables to support flexible product designs without schema changes.

When a policy activates, Enrollment publishes enrollment.policy.activated so that Eligibility and Billing can react.

Responsibilities

  • Accept quote creation requests and price them against Policy Admin product configuration
  • Drive quotes through the underwriting workflow (price → underwrite → issue/refuse/discard)
  • Bind issued quotes into active policies with coverage terms and elements
  • Manage in-force transactions: endorsements, cancellations, reinstatements, renewals
  • Enforce underwriting rules via the shared rule engine
  • Store flexible field values for configurable product attributes
  • Publish lifecycle events for Eligibility, Billing, and Notifications
  • Expose internal endpoints for Broker API and Group Scheme Service to list policies

Database

Schema: enrollment

TablePurpose
quotesQuote root aggregate with pricing, status, and product version reference
quote_eventsImmutable event log for quote state transitions
policiesActive policy records with account, broker, and term references
policy_termsCoverage period records (effective/expiry dates) per policy
policy_transactionsAll in-force changes (endorse, cancel, reinstate, renew) as transaction records
policy_elementsIndividual coverage items and riders within a policy term
underwriting_flagsFlags raised during underwriting that require manual review
quote_field_valuesConfigurable field values scoped to a quote
policy_field_valuesConfigurable field values scoped to a policy
transaction_field_valuesConfigurable field values scoped to a transaction
outboxTransactional outbox for reliable Kafka event publishing

API Routes

MethodPathAuthDescription
POST/quotesJWTCreate a new quote
GET/quotes/{locator}JWTGet quote by locator
PATCH/quotes/{locator}JWTUpdate quote document
PATCH/quotes/{locator}/priceJWTPrice a quote
PATCH/quotes/{locator}/underwriteJWTRun underwriting on a quote
PATCH/quotes/{locator}/issueJWTIssue (bind) a quote into a policy
PATCH/quotes/{locator}/refuseJWTRefuse a quote
PATCH/quotes/{locator}/discardJWTDiscard a draft quote
POST/quotes/{locator}/number/generateJWTGenerate a display quote number
GET/policies/{locator}JWTGet policy by locator
GET/policiesJWTList policies (filterable by account)
POST/policies/{locator}/cancelJWTCancel an active policy
POST/policies/{locator}/reinstateJWTReinstate a lapsed or cancelled policy
POST/policies/{locator}/renewJWTRenew a policy for a new term
POST/policies/{locator}/endorseJWTApply an endorsement transaction
POST/policies/{locator}/number/generateJWTGenerate a display policy number
GET/policies/{locator}/termsJWTList terms for a policy
GET/policies/{locator}/elementsJWTList active elements for a policy
GET/policies/{locator}/transactionsJWTList transactions for a policy
GET/transactions/{locator}JWTGet a transaction by locator
PATCH/transactions/{locator}/priceJWTPrice a pending transaction
PATCH/transactions/{locator}/underwriteJWTUnderwrite a pending transaction
PATCH/transactions/{locator}/applyJWTApply an approved transaction
PATCH/transactions/{locator}/declineJWTDecline a transaction
PATCH/transactions/{locator}/discardJWTDiscard a draft transaction
PATCH/transactions/{locator}/reverseJWTReverse an applied transaction

Events

Publishes

TopicWhen
enrollment.quote.createdA new quote is created
enrollment.policy.activatedA quote is issued and a policy becomes active
enrollment.policy.lapsedA policy lapses due to non-payment
enrollment.policy.cancelledA policy is cancelled

Consumes

The Enrollment service does not consume Kafka events. Changes are driven by external API calls.

Dependencies

ServiceHow used
Policy AdminFetches product configuration, benefit rules, and rule sets for pricing and underwriting

Key Design Decisions

Rule engine integration: Enrollment embeds the shared ruleengine library for in-process rule evaluation during underwriting. Rules are fetched from Policy Admin and persisted locally via ruleengine.NewWriter(gormDB) for fast repeated evaluation without cross-service calls on every request.

Field values for flexible products: Rather than schema migrations for every new product attribute, configurable fields are stored in *_field_values tables keyed to the quote, policy, or transaction locator. Field definitions are managed in Policy Admin and fetched at runtime.

Olly Health Insurance Platform