Backend / API

The regulated-finance BFF.

A TypeScript Express 5 service that owns provider secrets, identity bridging, money movement, invoicing, statements and reconciliation. Clients stay thin; the backend stays in charge.

At a glance

13
HTTP namespaces
206+
Endpoints
40
Prisma migrations
9
Provider integrations

Inside the BFF

Express boot → middleware → routers → controllers → providers + Postgres.

Rendering diagram…
Backend deep view · routers, controllers, providers, persistence

HTTP surface

Every namespace mounted in src/app.ts, with endpoint counts from route extraction.

Base pathPurposeEndpoints
/api/usersSignup, login, Cognito flows, profile, notifications, SumSub token / status, account deletion27
/api/ifIntegrated Finance clients, accounts, cards, beneficiaries, transfers, transactions, graphs, open banking, webhooks41
/api/sumsubSumSub webhook + SSE status stream2
/api/phylloPhyllo users, SDK tokens, work platforms, accounts, profiles, social / income data, webhooks36
/api/monite/commonCounterparts, addresses, bank accounts, contacts, VAT IDs27
/api/monite/entityEntities, roles, entity users, bank accounts, VAT IDs, settings19
/api/monite/payablesPayables and credit notes6
/api/monite/receivablesUnits, products, VAT rates, payment terms, invoices, recurrences20
/api/statementsAccount, confirmation, balance, fee and email statement generation5
/api/supportIntercom tickets, tickets metadata, tags, replies18
/api/support/kbIntercom knowledge base facade5
/api-docsSwagger UI · OpenAPI
/webhookGeneric placeholder webhook logger

Tech stack

Every layer of the runtime, with the file or surface that proves it.

Runtime
Node.js 20 · TypeScript
package.json, tsconfig.json
HTTP API
Express 5 · CORS · Helmet
src/app.ts
Docs
Swagger UI · swagger-jsdoc
/api-docs, src/swagger.ts
Database
PostgreSQL
Prisma datasource
ORM
Prisma Client 6 · 40 migrations
src/prisma/schema.prisma
Auth
AWS Cognito JWT · JWKS · refresh rotation
authMiddleware.ts, cognitoController.ts
Validation
Zod · express-validator
middleware/*
File / image
Multer · Sharp · AWS S3 SDK
profile + statement flows
PDF
Puppeteer · Handlebars · pdf-lib · pdf-lib-with-encrypt
statement controllers/templates
Notifications
OneSignal · Nodemailer
pushService.ts, emailService.ts
External HTTP
Axios
client/integrations/*
Tests
Jest · ts-jest · Supertest
single controller test
Deployment
Docker · PM2 · Bitbucket Pipelines · EC2
Dockerfile, bitbucket-pipelines.yml

Core flows

The chains the backend actually orchestrates day to day.

Signup, verification, login

Email + SMS OTP staged onboarding, Cognito user creation, admin-confirm bypass for dev, refresh-token rotation persisted in PostgreSQL.

KYC / KYB → financial provisioning

SumSub access token issuance, webhook upserts SumSubStatus, then Integrated Finance external user + bank account, then Monite entity / role / entity user.

Accounts, cards, transfers

Wraps Integrated Finance: client + account + card lifecycle, beneficiary requirements, transfer creation, card transaction authentication approval/reject, IF webhook reconciliation.

Statements & documents

Handlebars HTML → Puppeteer PDF → S3 → presigned URL. Account, confirmation, balance summary, statement of fees and password-protected statement by email.

Phyllo creator data

Create Phyllo user linked to cognitoId, SDK tokens, work platforms, profiles, audience, content, income transactions, payouts and balances. Webhook payloads stored in PhylloData.

Monite invoicing

Entities, roles, entity users, counterparts, products, VAT rates, payment terms, payables, receivables, recurring invoices and PDF generation.

Support & knowledge base

Intercom-backed: ticket lifecycle, replies, tagging, KB collections / sections / articles / search — all brokered server-side.

Notifications

OneSignal push and SMTP email with persisted Notification rows, send status and read/unread state per user.

Signup → login sequence

Rendering diagram…
Email + SMS verification, Cognito confirmation, refresh-token rotation

KYC approved → provider provisioning

Rendering diagram…
Sumsub → Integrated Finance → Monite, mirrored locally

Webhook fan-out

Provider events become Lobster-owned state — and an audit trail.

Rendering diagram…
Verify → normalize → persist → notify

Environment contract

The names of every secret the runtime expects. Values stay in the secret manager.

Runtime
  • NODE_ENV
  • PORT
  • DATABASE_URL
  • FRONTEND_URL
  • APP_PATH
Integrated Finance
  • IF_API_BASE_URL
  • IF_CLIENT_ID
  • IF_INSTANCE_ID
  • IF_OIDC_ISSUER
  • IF_TOKEN_ENDPOINT
  • IF_PRIVATE_KEY_PATH
Sumsub
  • SUMSUB_BASE_URL
  • SUMSUB_APP_TOKEN
  • SUMSUB_SECRET_KEY
  • SUMSUB_WEBHOOK_SECRET
Phyllo
  • PHYLLO_BASE_URL
  • PHYLLO_CLIENT_ID
  • PHYLLO_CLIENT_SECRET
AWS / Cognito / S3
  • AWS_REGION
  • COGNITO_USER_POOL_ID
  • COGNITO_CLIENT_ID
  • COGNITO_CLIENT_SECRET
  • AWS_S3_BUCKET
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
SMTP
  • SMTP_HOST
  • SMTP_PORT
  • SMTP_SECURE
  • SMTP_USER
  • SMTP_PASS
Monite
  • MONITE_CLIENT_ID
  • MONITE_SECRET
OneSignal
  • ONESIGNAL_APP_ID
  • ONESIGNAL_REST_API_KEY
Dev bypass
  • SMS_BYPASS_ENABLED
  • HARDCODED_SMS_OTP
  • EMAIL_BYPASS_ENABLED
  • HARDCODED_EMAIL_OTP

Deployment & operations

Rendering diagram…
Bitbucket Pipelines · SSH · Docker · PM2 · EC2

Security & production readiness

Findings from the system breakdown, surfaced honestly so they get fixed.

Webhook signature verification

High

Sumsub verification is commented out; IF webhook does not verify signatures. Raw-body HMAC must run before any DB write.

Unauthenticated finance routes

High

IF token / client routes, several IF account / beneficiary routes, Monite payables and common routes, and a user admin reset path lack auth.

Rate limiter target path

High

Limiter checks /api/users/signup but real routes are /signup/initiate, /login, /resend/*. Update path matching and broaden coverage.

Sensitive logs

High

SMTP options, Phyllo Basic auth headers, Cognito secret hash, raw webhook payloads logged in clear. Adopt redacted structured logging.

Secret material in repo

High

.env.prod and secret-keys/private-key.pem exist locally. .gitignore ignores .env* but not secret-keys/. Rotate and move to a secret manager.

Hardcoded webhook secret fallback

High

Sumsub handler has a literal fallback. Require SUMSUB_WEBHOOK_SECRET and fail closed on missing env.

Cognito JWT verification depth

Medium

Verifies signature + sub; should also check issuer, audience / client id and token use.

Express 5 with @types/express 4

Medium

Type drift between runtime and type packages.

Build / deploy config drift

Medium

PostgreSQL app paired with Mongo docker-compose; build copies .env but snapshot ships .env.prod.

Stale test suite

Medium

Only test hits GET /api/users which is not in the current route list.

Missing DTO / schema layer

Medium

Zod installed but not enforced at most route boundaries.

Client ↔ backend route drift

Medium

/if/transfers/company vs /organization, /users/sumsub/regenerate/:userId vs /sumsub/regenerate, etc.