- Introduction
- Assumptions
- System Overview
- Technical Architecture
- Authentication & Authorization
- KYC Process
- Investment Execution & Order Tracking
- Data Model & Database Design
- API Documentation
- Testing Strategy
- Logging, Error Handling & Monitoring
- Scalability & Deployment
- Future Enhancements
- Run the application
This project is designed for Cushon, a FinTech provider specializing in workplace savings and pensions. The goal of this application is to extend ISA investment options to retail customers, separate from the Employer-based offering, while ensuring:
- User authentication & MFA security
- KYC verification for compliance
- Asynchronous ISA fund execution & order tracking
- Scalability, auditability, and robust error handling
- Comprehensive automated testing coverage for reliability
-
Existing Cushon Customers (Employer-based) Can Open Personal ISA Accounts
- Users with employer-managed pensions can toggle between their employer pension profile and a personal ISA profile.
- New ISA investments should be separate from employer pensions.
-
Authentication & Authorization Are Managed by an External Service
- Cushon has an existing authentication system used by multiple applications.
- Our application integrates via REST or gRPC to handle user authentication and MFA.
- Role-based access control (RBAC) ensures permission management.
-
KYC Verification Is Provided by an External Service
- KYC is a common process across multiple Cushon applications.
- We integrate with an existing KYC microservice (REST/gRPC).
- Users must provide NiNo (National Insurance Number) and Proof of Address.
-
Investment Execution Is Handled Asynchronously
- A separate Order Execution Microservice handles actual investment processing.
- Our service queues investment orders for execution and tracks progress via RabbitMQ.
- Users receive real-time updates about order status and notifications (email/push) upon completion.
-
The Application Must Be Stateless and Horizontally Scalable
- No user sessions are stored on the backend.
- The API layer should be load-balanced and containerized (Docker/Kubernetes).
-
PostgreSQL Must Be Scalable While Maintaining ACID Compliance
- ISA investments must always show the most up-to-date data.
- Neon.tech PostgreSQL can be considered in the future for branching, replica testing, and scalable instances.
-
Logging, Error Handling, and Service Monitoring Are Critical
- Every user action (logins, investments, profile updates) is stored in an audit log.
- Service monitoring (Prometheus, Grafana, Datadog) ensures real-time health tracking.
- Automated error detection & alerts notify the team of potential failures.
-
Testing Strategy Must Ensure Reliability at Scale
- Unit and Mocking Tests for business logic.
- E2E Tests or Contract Testing to ensure APIs work correctly.
- Manual E2E Testing for new features as the application grows.
This application allows new and existing users to:
- New Users: Sign up, verify email & phone, complete KYC, and invest in an ISA.
- Existing Cushon Users: Toggle between their Employer Pension View and Personal ISA View.
- Invest in a single fund (future-proofed for multiple fund selection).
- Ensure ACID-compliant transactions for investment accuracy.
- Use a stateless backend to support horizontal scaling.
- Monitor order execution via RabbitMQ & notify users on completion.
Architecture Diagram (Cushon Diagram.excalidraw) can be imported in excalidraw if you want to edit it. Image is also available in the root of the project.
- Auth Service Integration: We integrate Cushon's existing Authentication Service via REST or gRPC.
- MFA Enforcement: Users must verify email, phone, and optionally enable Google Authenticator.
- Future Improvement: Support passwordless authentication (WebAuthn, Yubico).
- National Insurance Number (NiNo) verification
- Proof of Address submission (utility bill, bank statement)
- AML & fraud detection (via third-party APIs like SumSub, Onfido)
- User submits investment order.
- Order is queued in RabbitMQ.
- Order Execution Service processes the request asynchronously.
- Order status updates are pushed back to our service.
- Upon completion, users receive an email or mobile push notification.
Below is a simplified schema focusing on key tables:
Column | Type | Description |
---|---|---|
id |
UUID | Primary Key |
email |
TEXT | User's email (retrieved from Auth Service) |
mobile_number |
TEXT | User's mobile number (retrieved from Auth Service) |
account_type |
TEXT | EMPLOYER_PENSION , PERSONAL_ISA , or BOTH |
kyc_verified |
BOOLEAN | TRUE if the KYC service has approved the user |
created_at |
TIMESTAMP | Account creation date |
Note: No sensitive authentication data is stored here, as it's managed by the external Auth Service.
Column | Type | Description |
---|---|---|
id |
UUID | Primary Key |
user_id |
UUID | Foreign Key (Users Table) |
fund_id |
TEXT | Fund selected |
amount |
DECIMAL(10,2) | Investment amount |
created_at |
TIMESTAMP | Investment timestamp |
status |
TEXT | Investment status |
Service | Method | Endpoint | Description |
---|---|---|---|
Auth Service | GET |
/api/auth/me |
Fetch user profile (email, mobile, auth status) |
Auth Service | POST |
/api/auth/logout |
Log the user out |
KYC Service | GET |
/api/kyc/status |
Check if user has passed KYC |
KYC Service | POST |
/api/kyc/refresh |
Re-check KYC status if it's pending |
Method | Endpoint | Description |
---|---|---|
POST |
/api/investments |
Create a new ISA investment |
GET |
/api/investments |
Retrieve user's investment history |
GET |
/api/investments/:id |
Retrieve a specific investment |
We employ a multi-layered testing approach:
- Unit and Mocking Tests for business logic.
- E2E Tests or Contract Testing to ensure APIs work correctly.
- Manual E2E Testing for new features as the application grows.
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("User created investment", slog.String("user_id", userID), slog.Float64("amount", amount))
logger.Info("KYC check completed", slog.String("user_id", userID), slog.Bool("verified", true))
- Local Dev: Print logs in
JSON
format. - Production: Send logs to:
- AWS CloudWatch / Loki / Datadog.
- Elasticsearch for log searching.
- Centralized error handling middleware in the backend.
- Graceful degradation:
- If RabbitMQ fails, orders are retried.
- If the KYC service is down, the user is notified.
- Automated Alerts:
- Errors are logged and sent to Sentry, Datadog, or Prometheus.
- Prometheus & Grafana for real-time monitoring.
- Health checks via Pingdom or AWS CloudWatch.
- Alerts notify the team about failures before they impact users.
Component | Deployment Strategy |
---|---|
Go Backend | Containerized (Docker/Kubernetes) |
PostgreSQL | Managed DB (AWS RDS, GCP Cloud SQL, or Neon.tech) |
Frontend (React) | Deployed via CDN (CloudFront, Netlify, Vercel) |
Authentication | Cushon's Centralized Auth Service |
KYC Integration | REST/gRPC Microservice |
Order Execution | Separate microservice triggered via RabbitMQ |
- Partitioning (sharding) for performance.
- PgBouncer connection pooling to handle high request loads.
- CI/CD Pipelines (GitHub Actions, GitLab CI/CD, CircleCI).
- Rolling updates in Kubernetes to prevent downtime.
- Infrastructure as Code (Terraform, AWS CDK) for repeatable deployments.
- Multiple Fund Selections for ISA
- Real-time Investment Updates (WebSockets, SSE)
- Automated Risk Scoring for KYC
- ISA Portfolio Optimization (Robo-advisors)
- Hardware Security Key Support (WebAuthn/Yubico)
- Neon.tech PostgreSQL for branching & scalable datastore
- Node.js v20 or later
- Go 1.22 or later
- Docker and Docker Compose
- Make (optional, but recommended)
The services will be available at:
- Frontend: http://localhost:5173
- Backend: http://localhost:8080
- PostgreSQL: localhost:5432
-
Run PostgreSQL in Docker:
make run-postgres
-
Install go migrate tool:
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
-
Run database migrations:
make migrate-up
-
Start the backend in development mode:
make run
-
Register a user:
curl -X POST http://localhost:8080/api/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "password": "password123" }'
-
Install dependencies:
make frontend-install
-
Start the development server:
make frontend-dev
make run
- Run the backendmake test
- Run backend testsmake migrate-up
- Apply database migrationsmake migrate-down
- Revert database migrationsmake docker-down
- Stop all servicesmake frontend-install
- Install frontend dependenciesmake frontend-dev
- Start frontend development servermake frontend-build
- Build frontend for productionmake run-postgres
- Run PostgreSQL service
-
POST
/api/auth/login
- Login{ "email": "[email protected]", "password": "password123" }
-
POST
/api/auth/register
- Register{ "email": "[email protected]", "password": "password123" }
- GET
/api/investments
- List investments - POST
/api/investments
- Create investment{ "amount": 1000.00 }
- GET
/api/investments/:id
- Get investment details
- The application uses mock implementations for external services (Auth, KYC)
- JWT authentication is mocked for development
- CORS is configured to allow all origins in development
- Unit test and E2E test are not implemented
- Logging is not implemented
- Error handling is not implemented
- Service monitoring is not implemented