Infrastructure

All infrastructure is AWS, defined in Terraform under deploy/ and applied per environment. Resource names carry the site prefix (test or prod, e.g. prod-insight-api); the application identifier is insight. Every Lambda is created by the fmtf-module-lambda module (v2.1.0), which provisions the function, IAM role, log group, and Datadog monitors. Memory is the module default for every function.

Deployment

Three workflows drive deployment, one per trigger: on_pr.yaml, on_main.yaml and on_release.yaml. Each builds the Lambda tarball once and calls the shared deploy-env.yaml once per target, passing every per-target fact (account, region, state bucket, artifact bucket, legacy-table region) as an input. The continuous targets are the old test environment in the shared account (us-west-2), the test environment in its own account (299185625033, us-east-2) and staging; prod deploys from the published release’s tarball. Terraform authenticates to AWS with GitHub OIDC; there are no static credentials. Pull requests assume the read-only site-github-services-plan role and run terraform plan for every continuous target; pushes to main and published releases assume site-github-services-deploy and run terraform apply. Both roles, and the site-github-services-boundary permissions boundary every Lambda role carries, are owned by the infrastructure repo. The Terraform providers use the workflow’s credentials directly, with no further role assumption. State lives under terraform/insight/ in floatme-site-media for old test and prod, floatme-test-services-terraform-state for the new test account and floatme-staging-services-terraform-state for staging, locked by the terraform-locking table in each account. Lambda packages upload to the bucket named by the artifact_bucket variable (floatme-test-services-artifacts in the new test account, floatme-site-media elsewhere). The provider lock file is committed so every init resolves the same provider versions.

Peer service APIs (user-service, txn, underwriting) are resolved by name at plan time and addressed by convention (https://{id}.execute-api.{region}.amazonaws.com). A peer that has not yet deployed to an environment yields an empty URL and an account-wide execute-api:Invoke grant until the next deploy picks up its id, so a fresh environment comes up in two passes rather than failing the plan.

Lambda Functions

Function Trigger Timeout VPC Key IAM Permissions

site-insight-api

API Gateway site-insight (see API Gateway)

300s

Yes

site-pave Query/Get/Put/Delete; site-incomedetection and site-fmdatacapture PutItem; invoke User, Txn, Underwriting APIs; SageMaker InvokeEndpoint; pave, rds, growthbook secrets

site-insight-feeder

Kinesis site-txn-plaid-transactions (see Kinesis)

840s

Yes

site-pave Get/Put; Kinesis read; pave, growthbook, rds secrets

site-insight-miner

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

810s (90% of queue visibility timeout)

No

site-pave GetItem; SQS receive/delete; EventBridge PutEvents on default

site-insight-replay-feeder

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

840s

Yes

SQS receive/delete; pave, growthbook, rds secrets

site-insight-webhook

Shared webhooks API Gateway (see API Gateway)

840s

No

SQS SendMessage to site-insight-miner; pave/webhooks secret

site-insight-balance-alert

SQS site-insight-balance-alert-event-tap (batch 10)

27s (90% of queue visibility timeout)

No

site-pave Get/Put; user-balance-settings GetItem; locks Get/Put/Update/Query/Delete; invoke Underwriting API; segment secret

site-insight-institution-change-handler

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

108s (90% of queue visibility timeout)

Yes

site-pave BatchGet/Get/Put/Delete/Query and indexes; SQS receive/delete; rds secrets

site-insight-savings-snapshot

SQS site-insight-savings-snapshot-event-tap (batch 10)

108s (90% of queue visibility timeout)

No

site-pave PutItem; invoke Txn API; SQS receive/delete

VPC placement (private subnets floatme Private Subnet 1 and 2, security group floatme PrivateSG) is required for RDS access — see RDS.

API Gateway

Gateway Defined in Routing

site-insight (HTTP API)

deploy/lambda.tf

ANY /{proxy+} to site-insight-api; AWS IAM (SigV4) authorization; 30s integration timeout. Also mapped to insight.site.svc.floatme.io (deploy/domain.tf), an alias record in the infrastructure repo’s per-environment zone using its wildcard certificate; the execute-api endpoint stays enabled. Callers are FloatMe backend services and the global FloatMe API Gateway on behalf of authenticated mobile requests

Shared FloatMe webhooks gateway

infrastructure repo, aws/webhooks/

POST /v1/pave to site-insight-webhook. Authentication is the Lambda’s HMAC middleware (Pave-Signature header, WEBHOOK_TTL freshness window, default 3600s), not the gateway

SQS Queues

Queue Visibility Timeout Max Receive Purpose

site-insight-miner

900s

5

Miner jobs enqueued by the webhook Lambda

site-insight-replay-feeder

900s

5

Deferred transaction deletions from the Transactions Service

site-insight-balance-alert-event-tap

30s (AWS default)

5

new_account events tapped from EventBridge

site-insight-institution-change-handler-sqs-tap

120s

1

new_bank_account_added events tapped from EventBridge

site-insight-savings-snapshot-event-tap

120s

5

user_new_txns_batch_completed events tapped from EventBridge

Every queue has a dead-letter queue named <queue>-dlq.

The institution-change-handler queue has maxReceiveCount = 1: a message that fails once lands in the DLQ with no retry.

Kinesis

The feeder consumes the Transactions Service’s site-txn-plaid-transactions stream: batch size 100, starting position LATEST, no event filter. Each record is one page of a user’s Plaid transaction sync (user_id, transactions, removed, last_page).

EventBridge

All rules are on the default bus and target an SQS queue in SQS Queues. Event contracts are in Events.

Rule Pattern Target Queue State

balance_alert_rule

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

site-insight-balance-alert-event-tap

Enabled

account_change_detected_rule

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

site-insight-institution-change-handler-sqs-tap

account_change_handler_enabled variable (default ENABLED)

savings_snapshot_rule

source: txn-service.refiner, detail-type: user_new_txns_batch_completed

site-insight-savings-snapshot-event-tap

Enabled

The miner publishes to the same bus with source insight-service.miner.

DynamoDB Tables

All tables are referenced as data sources; none is created by this repository. Schemas are in DynamoDB Tables.

Table Region Consumers

site-pave

Current region (pave_table_region override)

api, feeder, miner, balance-alert, institution-change-handler, savings-snapshot

site-incomedetection

Current region

api (write only)

site-fmdatacapture

Current region

api (write only)

user-balance-settings

us-east-1 in prod; current region in test

balance-alert (read only)

locks

us-east-1 in prod; current region in test

balance-alert

RDS

Four Lambdas (api, feeder, replay-feeder, institution-change-handler) connect to the shared FloatMe PostgreSQL cluster through two pgx pools: main (site/rds/main) for writes and replica (site/rds/replica) for reads. Schema: PostgreSQL Schema.

The feeder opens a pool per execution environment and scales with Kinesis shard count, so its concurrency counts against the cluster’s max_connections.

SageMaker

The API Lambda invokes the incomedetection-inference-endpoint-site endpoint (env var INCOME_DETECTION_ML_ENDPOINT_NAME) during income detection. The endpoint is not managed by this repository.

Secrets Manager

Secrets are fetched once at cold start via BatchGetAndUnmarshalSecrets.

Secret Contents Consumers

site/pave

Pave API key

api, feeder, replay-feeder

site/pave/webhooks

Pave webhook signing secret

webhook

site/rds/main

RDS main credentials

api, feeder, replay-feeder, institution-change-handler

site/rds/replica

RDS read-replica credentials

api, feeder, replay-feeder, institution-change-handler

site/growthbook

GrowthBook SDK key and host

api, feeder, replay-feeder

site/segment

Segment write key

balance-alert

site/datadog/terraform

Datadog API and app keys

Terraform (SLOs, service definition)

Monitoring

Datadog monitors and SLOs exist in prod only (local.create_datadog_monitors in deploy/datadog.tf). Alerts outside prod go unread, and the old and new test accounts both deploy as test, so Datadog would reject the second account’s identical monitors as duplicates.

Three Datadog SLOs — Lambda errors, throughput, and latency — each with a 99.9% target and 99.99% warning over 7-day and 30-day windows, cover api, balance-alert, feeder, miner, replay-feeder, and webhook. The institution-change-handler and savings-snapshot Lambdas have module-provisioned monitors but are in no SLO. The Datadog service definition registers insight as tier 1.