Skip to content

Mint

A production-style fintech platform built as a polyglot microservices monorepo. Covers authentication, multi-currency wallets, real-time payments, KYC, fraud detection, analytics, social features, webhooks, an admin console, and a tamper-proof audit log.


What's Inside

12 independently deployable services communicating over HTTP, gRPC, and Kafka. Two are written in Python (FastAPI), nine in TypeScript (NestJS), plus a Next.js 15 web app.

Layer What's there
API gateway nginx — routing, rate limiting, SSE proxy
Auth RSA-signed JWTs, JWKS endpoint, refresh tokens, RBAC
Payments Idempotent transfers with a formal state machine
Fraud Rules-based scoring engine, called synchronously on every transaction
Wallets gRPC settlement interface with idempotent debit/credit
KYC Document upload → tier promotion → spend limit enforcement
Analytics Kafka-driven spend aggregation, category classification, budget alerts
Social Contacts, money requests with expiry, bill splits
Webhooks User-registered endpoints, HMAC-signed payloads, delivery retry
Audit Immutable append-only log — PostgreSQL trigger prevents UPDATE/DELETE
Observability End-to-end distributed traces across HTTP, gRPC, and Kafka

Key Design Properties

Every transaction is safe to retry. The transactions service accepts an Idempotency-Key header. Duplicate requests return the cached response from Redis rather than executing twice.

Fraud scores every payment before any money moves. The fraud service (gRPC-only) runs six rules in parallel and returns ALLOW / REVIEW / BLOCK. Blocked transactions never reach wallet settlement.

KYC gates spend limits. The kyc service exposes per-transaction, daily, and monthly caps via gRPC. Transactions that exceed the caller's tier are rejected before the fraud check.

Audit trail is tamper-proof. Every Kafka event from every service is written to an append-only PostgreSQL table. A database trigger rejects any UPDATE or DELETE.

Traces span async boundaries. OpenTelemetry trace context is forwarded in Kafka message headers via KafkaTraceInterceptor. A single transfer request produces one trace that spans fraud scoring, wallet debit/credit, analytics ingestion, notification delivery, and webhook dispatch.

Database isolation. Each service owns exactly one PostgreSQL database with its own credentials. No service can query another service's tables.


Services

Service Stack Port Description
auth Python / FastAPI 4001 JWT issuance, refresh, RBAC
wallet Python / FastAPI 4002 Balances, gRPC settlement interface
transactions NestJS 4003 Transfers, top-ups, idempotency
fraud NestJS (gRPC only) 50052 Real-time fraud scoring
kyc NestJS 4004 Document upload, tier management
analytics NestJS 4005 Spend insights, category budgets
notifications NestJS 4006 Persistent notifications + SSE stream
social NestJS 4007 Contacts, money requests, bill splits
webhook NestJS 4008 User-registered webhooks + delivery log
admin NestJS 4009 Admin console — user management, fraud review
audit NestJS 4010 Immutable append-only audit log

Tech Stack

Layer Technology
API services NestJS (TypeScript), FastAPI (Python)
Databases PostgreSQL (one DB per service), Prisma, Alembic
Async messaging Apache Kafka
Internal RPC gRPC
Cache / queues Redis, BullMQ
Object storage MinIO (S3-compatible)
API gateway nginx
Observability OpenTelemetry, Grafana Tempo, Grafana
Containerisation Docker, Docker Compose
Testing Jest (NestJS), pytest + pytest-asyncio (Python)
CI GitHub Actions