Architecture

System Overview

The Underwriting Service is an event-driven microservice that evaluates user eligibility for float and loan products through a sophisticated rules engine. It exposes both synchronous REST API endpoints and processes asynchronous events from other Float services.

Key Capabilities

  • Rule Evaluation Engine: Executes complex rule sets to determine user eligibility

  • Float Profile Management: Stores and manages user float and loan settings, limits, and fee structures

  • Continuous Float Increase (CFI): Automatically adjusts float limits based on user behavior and history

  • Eligibility Determinization: Provides comprehensive decision-making for underwriting requests

  • Event-Driven Processing: Consumes and processes events from related services

Underwriting API Component

system context underwriting api

High-Level Architecture

The system is divided into three layers: API Layer, Processing Layer, and Data Layer.

Layer Components

API Layer

REST API Gateway (AWS Lambda) - Receives eligibility check requests - Delegates to processing layer - Returns decisions to clients

Processing Layer

Event-driven workers communicating via SQS and processing results - Rule Runner: Executes rules and retrieves evaluation data - Result Runner: Aggregates rule outcomes into final decisions - Event Handlers: React to float creation, profile updates

Data Layer

Persistent storage and event stream - DynamoDB: Primary data store (profiles, rules, results) - SQS: Task queues for background processing - EventBridge: Event routing and notifications - Kinesis: Event streams for analytics and audit

Component Interactions

The Underwriting Service integrates multiple AWS services in an event-driven architecture:

┌─────────────────────────────────────────────────────────────┐
│                    External Clients                         │
│              (Mobile App, Backend Services)                 │
└───────────────────────┬─────────────────────────────────────┘
                        │ HTTP Requests
                        ▼
        ┌───────────────────────────────┐
        │      API Gateway              │
        │   (Authorization/Routing)     │
        └───────────────────┬───────────┘
                            │ Invoke
                            ▼
            ┌───────────────────────────────┐
            │  API Lambda                   │
            │  ✓ Validate requests          │
            │  ✓ Fetch float profiles       │
            │  ✓ Determine eval strategy    │
            └────┬─────────────────┬────────┘
                 │                 │
      ┌──────────┴──────┐   Query  │
      │                 ▼          ▼
      │         ┌──────────────────────┐
      │         │  DynamoDB            │
      │         │  ✓ Profiles          │
      │         │  ✓ Rulebooks         │
      │         │  ✓ Evaluation Results│
      │         │  ✓ Historical Evals  │
      │         │  ✓ Rule Outcomes     │
      │         └──────────────────────┘
      │                 ▲
      │                 │ Read/Write
      │
   Publish Task
      │
      ▼
┌──────────────────┐
│  SQS Queue       │
│  (Eval Tasks)    │
└─────────┬────────┘
          │ Consume
          ▼
┌──────────────────────────┐              ┌──────────────────┐
│  Rule Runner Lambda      │              │  EventBridge     │
│  ✓ Gather user data      │──Results────▶│  ✓ Route events  │
│  ✓ Execute rules         │              │  ✓ Trigger       │
│  ✓ Store outcomes        │              │    handlers      │
└──────────────────────────┘              └────────┬─────────┘
            │                                      │
            │ Queue aggregation                    │ Publish events
            ▼                                      │
┌──────────────────────────┐                       │
│ Result Runner Lambda     │                       │
│ ✓ Aggregate outcomes     │                       │
│ ✓ Apply precedence       │          ┌────────────┴──────────┐
│ ✓ Final decision         │          │                       │
│ ✓ Store evaluation       │          ▼                       ▼
└──────────────────────────┘  ┌──────────────────┐  ┌─────────────────┐
            │                 │ Float Created    │  │ Profile Update  │
            │                 │ Handler Lambda   │  │ Handler Lambda  │
            └─────────────────┤ ✓ Create hist    │  │ ✓ Invalidate    │
                              │   eval           │  │   cache         │
                              │ ✓ Update state   │  │ ✓ Notify        │
                              └──────────────────┘  └─────────────────┘

Data Flow Summary: 1. Client requests eligibility check via API Gateway 2. API Lambda determines if evaluation can be cached or needs processing 3. For deferred evals: Task published to SQS queue 4. Rule Runner consumes task, executes rules, stores outcomes 5. Result Runner aggregates outcomes into final decision 6. Events trigger handlers for state updates (float creation, profile changes)

Request Flow: Float Eligibility Check

Here’s the typical flow when a client requests an eligibility check:

  1. Client Request: Mobile app or backend service calls /v1/{user_id}/underwriting/eligibility

  2. API Handler: API Lambda authenticates request and validates input parameters

  3. Profile Lookup: Retrieves current user float profile from DynamoDB

  4. Rule Retrieval: Fetches applicable rulebooks based on user characteristics (A/B testing, feature flags)

  5. Evaluation:

    • Can be immediate (cached evaluation from previous check)

    • Or deferred (publishes task to SQS for background processing)

  6. Result Determination: Aggregates rule outcomes to produce final eligibility decision

  7. Response: Returns decision, approved amounts, CFI data, and other metadata

Asynchronous Processing Flow

For deferred evaluations, the system uses event-driven background processing:

Eligibility Check Request
    ↓
[Decision: Immediate or Deferred?]
    ├─→ IMMEDIATE: Return cached result
    └─→ DEFERRED:
        ├─ Publish evaluation task to SQS
        │
        ├─→ Rule Runner Lambda consumes task
        │   ├ Gathers rule evaluation data
        │   ├ Executes individual rules
        │   └ Stores RuleOutcome entities
        │
        ├─→ Result Runner Lambda aggregates results
        │   ├ Retrieves all RuleOutcomes
        │   ├ Applies priority/precedence logic
        │   └ Creates EvaluationResult
        │
        └─→ Client polls for result
            (or receives notification via callback)

Data Flow: Decision Determination

The flow from rules to final decision involves several processing stages:

Stage Input Output

Rule Execution

Rule definition + User data

Individual RuleOutcome (pass/fail/unknown)

Result Aggregation

Array of RuleOutcomes

Intermediate decision state + metadata

Priority Application

Multiple rulebooks with priority order

Superseding rulebook selection

Final Decision

Selected rulebook outcomes

Approved/Denied + approved amounts

See Rule Engine Guide for detailed flow diagrams.

External Service Integration

The Underwriting Service integrates with multiple external services:

Service Integration Type Purpose

User Service

REST API calls

Retrieve user demographics, history

Float Service

Event streams + REST APIs

Float lifecycle coordination

Transaction Service

REST API calls

Access transaction history, spending patterns

Segment

Event dispatch

Analytics and event tracking

Datadog

Metrics/Logs

Monitoring and observability

Deployment Architecture

The service is deployed using Terraform for infrastructure management.

Environment Configuration

Staging

AWS managed services - Dedicated DynamoDB tables - Test rulebooks deployed - Separate SQS queues

Production

AWS managed services - High-availability configuration - Auto-scaling enabled - Encryption enabled - VPC isolation - Enhanced monitoring

See Deployment Guide for detailed infrastructure setup.

Scalability & Performance Considerations

Horizontal Scaling

  • Lambda Functions: Auto-scale based on SQS queue depth

  • DynamoDB: Configured with auto-scaling read/write capacity

  • Queues: SQS provides built-in scaling for task distribution

Caching Strategy

  • Rulebook Caching: TTL-based cache in memory (default: 60 minutes)

  • Evaluation Results: Short-lived cache for repeated checks within time window

Performance Optimization

  • Parallel Rule Execution: Rules evaluated concurrently where possible

  • Result Streaming: Large result sets streamed to prevent memory bloat

  • Query Optimization: GSI (Global Secondary Indexes) used for efficient lookups

Security Model

  • Authentication: API Gateway with authorization

  • Data Encryption:

    • In-transit: TLS/HTTPS required

    • At-rest: DynamoDB encryption enabled

    • Secrets: AWS Secrets Manager

  • IAM Permissions: Least-privilege roles per Lambda function

  • VPC Isolation: Optional private VPC deployment

Monitoring & Observability

The service is instrumented with comprehensive logging and metrics:

  • CloudWatch Logs: All Lambda executions logged

  • CloudWatch Metrics: Custom metrics for eligibility decisions, latency, errors

  • Datadog Integration: Centralized monitoring dashboard

  • Distributed Tracing: X-Ray for request tracing (optional)

See Monitoring section for dashboard setup.

See Also