Infrastructure

All infrastructure is managed via Terraform in deploy/. The Terraform module uses the fmtf-module-lambda reusable module for each Lambda function.


Terraform File Layout

File Contents

deploy/main.tf

Providers, locals, data sources for all tables/streams/queues, SQS queue resources, EventBridge rules and targets, API Gateway HTTP API

deploy/lambda.tf

All Lambda module definitions (API, feeder, miner, replay-feeder, webhook, balance-alert, income-signaller, funds-notifier, institution-change-handler)

deploy/sqs.tf

institution_change_handler_event_tap and its DLQ (the other SQS resources are defined inline in main.tf)

deploy/variables.tf

All input variables with defaults

deploy/secrets.tf

Locals for Secrets Manager secret names; data sources for all secrets

deploy/vpc.tf

VPC, subnet, and security group data sources

deploy/datadog.tf

Datadog SLOs (error, throughput, latency) and service definition

deploy/terraform.tf

Terraform backend and required provider versions


Lambda Functions

All Lambdas are deployed via the fmtf-module-lambda module (v1.4.10). The module provisions the Lambda function, IAM execution role, CloudWatch log group, Datadog monitors, and optional VPC placement.

Lambda Name Timeout Trigger VPC

prod-insight-api

300s

API Gateway (HTTP, IAM auth, ANY /{proxy+})

Private subnets + PrivateSG (required for RDS access)

prod-insight-feeder

840s

Kinesis prod-txn-plaid-transactions (batch: 100, LATEST)

No VPC

prod-insight-miner

90% of miner SQS visibility timeout (default: 810s)

SQS prod-insight-miner (batch: 10, window: 2s, ReportBatchItemFailures)

No VPC

prod-insight-replay-feeder

840s

SQS prod-insight-replay-feeder (batch: 20, window: 1s)

No VPC

prod-insight-webhook

840s

API Gateway (implicit, Pave webhook endpoint)

No VPC

prod-insight-balance-alert

90% of balance-alert SQS visibility timeout

SQS prod-insight-balance-alert-event-tap (batch: 10)

No VPC

prod-insight-income-signaller

840s

Kinesis prod-txn-floatme-transactions (batch: 100, LATEST)

No VPC

prod-insight-funds-notifier

90% of income event tap SQS visibility timeout

SQS prod-income-event-tap (batch: 10)

No VPC

prod-insight-institution-change-handler

90% of institution change SQS visibility timeout (120s → 108s)

SQS prod-insight-institution-change-handler-sqs-tap (batch: 10)

Private subnets + PrivateSG (required for RDS access)

The miner timeout is set to floor(visibility_timeout * 0.9). With the default miner_sqs_visibility_timeout of 900s, the miner timeout is 810s. This ensures the Lambda always finishes before the SQS message becomes visible again.

Key Environment Variables

Variable Lambda(s) Description

DYNAMO_TABLE

api, miner, balance-alert, institution-change-handler, funds-notifier

prod-pave table name

EXPENSE_TTL

api, miner

Days to add to due date when computing recurring/ritual TTL (default: 1)

CASH_ADVANCE_SCORE_TTL

miner

Days before cash-advance score expires (default: 30)

PAVE_TRANSACTION_LIMIT

miner

Max number of transactions to send Pave per mining request (default: 10)

EVENTBRIDGE_AWS_REGION

miner, income-signaller

Region for the EventBridge default bus

SQS_ENDPOINT

webhook

URL of the miner SQS queue (webhook enqueues mining work here)

WEBHOOK_TTL

webhook

Webhook timestamp freshness window / replay protection (default: 3600s). The webhook handler (pkg/middlewares/webhook.go) rejects any request whose Pave-Signature timestamp differs from the current time by more than this value.

NOTIFICATION_FLAG

balance-alert, funds-notifier

Boolean env var controlling whether Segment notifications are actually dispatched (enable_balance_alert_notification, default: true)

CC_NOTIFICATION_BUFFER_DAYS

funds-notifier

Days to suppress duplicate credit-card funds notifications (default: 2)

MIN_INCOME_AMOUNT

api

Minimum income amount for income detection (hardcoded: -200)

MIN_INCOME_METHOD_C

api

Minimum valid income amount for Method C (default: -150)

MIN_JW_SCORE_METHOD_C

api

Minimum Jaro-Winkler score for transaction name matching in Method C (default: 0.8)

EXTENDED_PAYBACK_START_DAYS

api

Days from today before extended payback window begins (default: 28)

EXTENDED_PAYBACK_END_DAYS

api

Days from today to end of extended payback window (default: 42)

INCOME_DETECTION_ML_ENDPOINT_NAME

api

SageMaker endpoint name for ML income classification

INCOME_DETECTION_DYNAMO_TABLE

api

prod-incomedetection table name

FM_DATACAPTURE_DYNAMO_TABLE

api

prod-fmdatacapture table name


SQS Queues

Queue Name Visibility Timeout Max Receive Count DLQ

prod-insight-miner

900s (configurable via miner_sqs_visibility_timeout)

5

prod-insight-miner-dlq

prod-insight-replay-feeder

900s (configurable via replay_feeder_sqs_visibility_timeout)

5

prod-insight-replay-feeder-dlq

prod-insight-balance-alert-event-tap

Default (not set in Terraform; AWS default is 30s)

5

prod-insight-balance-alert-event-tap-dlq

prod-income-event-tap

Default

N/A (no redrive policy defined)

None

prod-insight-institution-change-handler-sqs-tap

120s

1

prod-insight-institution-change-handler-sqs-tap-dlq

The institution-change-handler queue has maxReceiveCount = 1 — a message that fails its single processing attempt is moved to the DLQ immediately with no automatic retries. The SQS visibility timeout only controls how long a message is invisible while being processed; it does not provide additional retry attempts. This aggressive DLQ behaviour is intentional: both delete operations are idempotent, so re-processing a failed message is safe if needed via the DLQ, but automatic retries are not warranted.

EventBridge Rules

All three rules operate on the default event bus. Rules and their SQS targets are defined in deploy/main.tf.

Rule Resource Event Pattern Target Queue Enabled

aws_cloudwatch_event_rule.balance_alert_rule

source: txn-service.feeder, detail-type: new_account

prod-insight-balance-alert-event-tap

Always (no state control)

aws_cloudwatch_event_rule.income_detected_rule

source: insight-service.income, detail-type: income_txn, amount < -cc_notification_limit

prod-income-event-tap

Always (no state control)

aws_cloudwatch_event_rule.account_change_detected_rule

source: txn-service.api, detail-type: new_bank_account_added

prod-insight-institution-change-handler-sqs-tap

Controlled by account_change_handler_enabled variable (default: "ENABLED")


Kinesis Streams

Stream Name Consumer Lambda Notes

prod-txn-plaid-transactions

prod-insight-feeder

Batch size: 100, position: LATEST. Produces Plaid transaction webhooks that trigger Pave insight mining.

prod-txn-floatme-transactions

prod-insight-income-signaller

Batch size: 100, position: LATEST. FloatMe-normalized transaction stream; signaller filters for same-day negative-amount transactions.


DynamoDB Tables (Terraform)

Table Local Name Terraform Resource Type

prod-pave

pave_service_table_name${environment}-pave

data.aws_dynamodb_table.pave (referenced, not created here)

prod-incomedetection

incomedetection_dynamo_table${environment}-incomedetection

data.aws_dynamodb_table.incomedetection (referenced)

prod-fmdatacapture

fmdatacapture_dynamo_table${environment}-fmdatacapture

data.aws_dynamodb_table.fmdatacapture (referenced)

user-balance-settings

user_settings_table_name

data.aws_dynamodb_table.user_settings (legacy, us-east-1)

locks

locks_table_name

data.aws_dynamodb_table.locks (legacy, us-east-1)


Secrets Manager

All secrets are fetched at Lambda startup via BatchGetAndUnmarshalSecrets. Secret names follow {environment}/{service} convention.

Secret Name Local Used By

{environment}/pave

sm_pave_name

feeder, miner, webhook (Pave API credentials)

{environment}/pave/webhooks

sm_pave_webhooks_name

webhook Lambda (Pave webhook signing key)

{environment}/rds/main

sm_rds_main_name

api, institution-change-handler (RDS write connection)

{environment}/rds/replica

sm_rds_replica_name

api, institution-change-handler (RDS read connection)

{environment}/segment

sm_segment_name

balance-alert, funds-notifier (Segment write key)

{environment}/growthbook

sm_growthbook_name

api, feeder, replay-feeder (GrowthBook SDK key)


VPC Configuration

Two Lambdas require VPC placement for private RDS access:

Resource Value

VPC

floatme (tagged Name=floatme)

Private Subnet 1

Tagged Name=floatme Private Subnet 1

Private Subnet 2

Tagged Name=floatme Private Subnet 2

Security Group

Tagged Name=floatme PrivateSG

Lambdas in VPC: prod-insight-api, prod-insight-institution-change-handler.


Datadog Monitoring

Three SLOs are defined in deploy/datadog.tf, covering all eight non-institution-change-handler Lambdas (api, balance-alert, feeder, funds-notifier, income-signaller, miner, replay-feeder, webhook):

SLO Timeframes Targets

[AWS][prod-insight] Lambda Errors SLO

7d, 30d

Target: 99.9%, Warning: 99.99%

[AWS][prod-insight] Lambda Throughput SLO

7d, 30d

Target: 99.9%, Warning: 99.99%

[AWS][prod-insight] Lambda Latency SLO

7d, 30d

Target: 99.9%, Warning: 99.99%

The Datadog service definition (service_definition_yaml) registers the service under the insight application with a Tier 1 designation, linking to the GitHub repo and the Antora-hosted docs at https://docs.floatme.io/insight-service.


Key Terraform Variables

Variable Default Description

miner_sqs_visibility_timeout

900

SQS visibility timeout for the miner queue (seconds). Lambda timeout is set to 90% of this.

miner_sqs_batch_size

10

Number of SQS messages per miner invocation

miner_batch_window

2

Seconds the miner waits to buffer messages before invoking

pave_score_ttl

30

Days before a cash-advance score expires in DynamoDB

pave_transaction_limit

10

Max recent transactions sent to Pave per mining request

pave_expense_ttl

1

Days added to due date when computing recurring/ritual TTL

cc_notification_limit

11999

Income amount threshold in cents for credit card funds notification (i.e. $119.99)

cc_notification_buffer_days

2

Days to suppress duplicate credit-card notifications

extended_payback_start_days

28

Days until extended payback window opens (4 weeks)

extended_payback_end_days

42

Days until extended payback window closes (6 weeks)

account_change_handler_enabled

"ENABLED"

State of the account_change_detected_rule EventBridge rule

enable_balance_alert_notification

true

Master switch for Segment notification dispatch