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 |
|---|---|---|---|---|
|
API Gateway |
300s |
Yes |
|
|
Kinesis |
840s |
Yes |
|
|
SQS |
810s (90% of queue visibility timeout) |
No |
|
|
SQS |
840s |
Yes |
SQS receive/delete; pave, growthbook, rds secrets |
|
Shared webhooks API Gateway (see API Gateway) |
840s |
No |
SQS SendMessage to |
|
SQS |
27s (90% of queue visibility timeout) |
No |
|
|
SQS |
108s (90% of queue visibility timeout) |
Yes |
|
|
SQS |
108s (90% of queue visibility timeout) |
No |
|
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 |
|---|---|---|
|
|
|
Shared FloatMe webhooks gateway |
|
|
SQS Queues
| Queue | Visibility Timeout | Max Receive | Purpose |
|---|---|---|---|
|
900s |
5 |
Miner jobs enqueued by the webhook Lambda |
|
900s |
5 |
Deferred transaction deletions from the Transactions Service |
|
30s (AWS default) |
5 |
|
|
120s |
1 |
|
|
120s |
5 |
|
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 |
|---|---|---|---|
|
|
|
Enabled |
|
|
|
|
|
|
|
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 |
|---|---|---|
|
Current region ( |
api, feeder, miner, balance-alert, institution-change-handler, savings-snapshot |
|
Current region |
api (write only) |
|
Current region |
api (write only) |
|
us-east-1 in prod; current region in test |
balance-alert (read only) |
|
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 |
|---|---|---|
|
Pave API key |
api, feeder, replay-feeder |
|
Pave webhook signing secret |
webhook |
|
RDS main credentials |
api, feeder, replay-feeder, institution-change-handler |
|
RDS read-replica credentials |
api, feeder, replay-feeder, institution-change-handler |
|
GrowthBook SDK key and host |
api, feeder, replay-feeder |
|
Segment write key |
balance-alert |
|
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.