-->
Company: MonieWorld (UK-based Fintech Startup)
Role: Founding Senior Frontend Engineer
Project Type: Wise Competitor, International Money Transfer Platform
Duration: Founding team member through product launch and scale
Market: UK → International remittances
MonieWorld is a fintech platform enabling international money transfers from the UK, competing directly with established players like Wise (formerly TransferWise). As the founding senior frontend engineer, I architected and built the entire frontend infrastructure from the ground up, establishing patterns and systems that became the foundation for all subsequent development.
The platform, while supports only the UK and Nigeria right now, was designed to scale globally, supporting transfers to every currency in the world, which was a requirement that fundamentally shaped the architectural decisions and development approach.
Launch Performance
Technical Achievements
Feature Organization (50+ Features)
The application was structured using DDD principles to handle the complexity of international money transfers across multiple currencies, payment methods, and regulatory requirements.
monieworld/
├── apps/
│ └── web/
│ ├── features/
│ │ ├── send-money/ # Core domain
│ │ │ ├── enter-amount/
│ │ │ ├── select-recipient/
│ │ │ └── review-transaction/
│ │ ├── payments/ # Core domain
│ │ │ ├── card-payment/
│ │ │ ├── digital-wallet/
│ │ │ └── bank-payment/
│ │ ├── recipients/ # Core domain
│ │ │ ├── add-recipient/
│ │ │ ├── verify-recipient/
│ │ │ └── recipient-list/
│ │ ├── currencies/ # Core domain
│ │ │ ├── exchange-rates/
│ │ │ ├── currency-selector/
│ │ │ └── conversion-calculator/
│ │ ├── kyc/ # Core domain
│ │ │ ├── identity-verification/
│ │ │ ├── document-upload/
│ │ │ └── compliance-checks/
│ │ └── accounts/ # Core domain
│ │ ├── registration/
│ │ ├── profile/
│ │ └── security/
│ └── shared/
│ ├── ui/ # Shared features
│ │ ├── forms/
│ │ ├── layouts/
│ │ └── notifications/
│ ├── validation/ # Shared features
│ ├── api-client/ # Shared features
│ └── utils/ # Shared features
├── lib/
│ ├── kamona-ui/ # Design system
│ ├── payment-sdk/ # Payment abstraction
│ ├── truelayer-sdk/ # Banking integration
│ ├── checkout-sdk/ # Card payments
│ ├── email-templates/ # Transactional emails
│ ├── feature-flags/ # Kill switches
│ └── shared-utils/ # Common utilities
DDD Principles Applied:
Core Domains (Root Level)
Each core domain contained its bounded context with:
Shared Domains
Why DDD for 50+ Features?
Challenge: Design system to support transfers in ALL world currencies, not just major ones.
Complexity:
Architecture Time Investment: The currency architecture alone required significant upfront investment to ensure it could scale globally without requiring rewrites for each new currency addition.
Solution:
Currency Configuration System
interface CurrencyConfig {
code: string; // ISO 4217
symbol: string;
decimals: number;
minAmount: number;
maxAmount: number;
supportedPaymentMethods: PaymentMethod[];
regulatoryLimits: RegulatoryLimit[];
formatting: CurrencyFormatting;
}
Dynamic Currency Loading
Exchange Rate Management
Currency-Aware Components
Result:
These aren’t vanity metrics, in fintech, comprehensive testing is regulatory and business-critical.
What We Tested:
Testing Patterns:
// Example: Currency conversion testing
describe("CurrencyConverter", () => {
it("converts GBP to EUR with correct exchange rate", () => {
const converter = new CurrencyConverter(exchangeRateService);
const result = converter.convert(100, "GBP", "EUR");
expect(result.amount).toBe(117.5);
expect(result.rate).toBe(1.175);
});
it("applies correct decimal rounding for JPY", () => {
const converter = new CurrencyConverter(exchangeRateService);
const result = converter.convert(100, "GBP", "JPY");
expect(result.amount).toBe(18500); // No decimals for JPY
});
it("throws error for unsupported currency pairs", () => {
const converter = new CurrencyConverter(exchangeRateService);
expect(() => {
converter.convert(100, "USD", "INVALID");
}).toThrow("Unsupported currency");
});
});
Coverage Areas:
What We Tested:
Critical E2E Test Scenarios:
Transfer Flow (Happy Path)
test("User can complete international transfer", async ({ page }) => {
// 1. Login
await page.goto("/login");
await page.fill('[data-testid="email"]', "[email protected]");
await page.fill('[data-testid="password"]', "password");
await page.click('[data-testid="login-button"]');
// 2. Select recipient
await page.click('[data-testid="new-transfer"]');
await page.selectOption('[data-testid="recipient"]', "John Doe - EUR");
// 3. Enter amount
await page.fill('[data-testid="send-amount"]', "1000");
await expect(page.locator('[data-testid="receive-amount"]')).toContainText(
"1175.00"
);
// 4. Select payment method
await page.click('[data-testid="payment-method-card"]');
// 5. Complete payment
await page.fill('[data-testid="card-number"]', "4242424242424242");
await page.fill('[data-testid="card-expiry"]', "12/25");
await page.fill('[data-testid="card-cvc"]', "123");
await page.click('[data-testid="submit-payment"]');
// 6. Verify success
await expect(page.locator('[data-testid="success-message"]')).toBeVisible();
await expect(
page.locator('[data-testid="transfer-reference"]')
).toContainText(/TR-\d+/);
});
Payment Method Coverage
Error Scenario Coverage
Test Environment Setup:
Jenkins Pipeline with Quality Gates:
pipeline {
stages {
stage('Install') {
steps {
sh 'npm ci'
}
}
stage('Lint') {
steps {
sh 'npm run lint'
}
}
stage('Type Check') {
steps {
sh 'npm run type-check'
}
}
stage('Unit Tests') {
steps {
sh 'npm run test:unit'
}
post {
always {
junit 'coverage/junit.xml'
publishHTML([
reportDir: 'coverage',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
}
stage('E2E Tests') {
steps {
sh 'npm run test:e2e'
}
}
stage('Build') {
steps {
sh 'npm run build'
}
}
stage('Docker Build') {
steps {
sh 'docker build -t monieworld:${BUILD_NUMBER} .'
}
}
stage('Deploy') {
steps {
sh './deploy.sh'
}
}
}
post {
failure {
// Notify team on Slack
}
}
}
Quality Gates Enforced:
Result:
Problem: Need to support multiple payment methods (cards, Apple Pay, Google Pay) with different SDKs, authentication flows, and error handling patterns.
Complexity:
Solution:
Custom SDK Development:
Result:
Context: Started as solo frontend engineer, then worked with enterprise architect who brought advanced patterns and practices.
Initial Phase (Solo):
Enterprise Architect Collaboration:
What I Learned:
Knowledge Transfer Process:
Application to MonieWorld:
Candid Reflection: “I couldn’t even comprehend half of it for quite a while”. The enterprise architect introduced concepts that took months to fully understand and apply effectively. This wasn’t a weekend learning curve; it was a fundamental shift in how I approached software architecture.
Outcome:
Problem: Design system to support ALL world currencies (150+) with different rules, formats, and constraints.
Time Investment: The currency architecture alone required extensive upfront development time to ensure global scalability without future rewrites.
Complexity Factors:
Technical Complexity:
Business Complexity:
Architectural Decisions:
1. Configuration-Driven System
2. Currency Service Abstraction
interface CurrencyService {
getSupportedCurrencies(): Currency[];
getExchangeRate(from: string, to: string): ExchangeRate;
formatAmount(amount: number, currency: string): string;
validateAmount(amount: number, currency: string): ValidationResult;
getSupportedPaymentMethods(currency: string): PaymentMethod[];
getRegulatoryLimits(fromCurrency: string, toCurrency: string): Limits;
}
3. Real-Time Exchange Rate Management
4. Currency-Aware Components
5. Testing Currency Logic
Result:
User initiates transfer (selects currency pair)
↓
Currency service validates pair & fetches rates
↓
User enters amount (currency-aware validation)
↓
Payment method selection UI
(filtered by currency support)
↓
Payment abstraction layer
↓
┌───┴───┬─────────┬──────────┐
↓ ↓ ↓ ↓
Cards Apple Pay Google Pay Bank
↓ ↓ ↓ ↓
Checkout Apple Google TrueLayer
SDK SDK SDK SDK
↓ ↓ ↓ ↓
└───┬───┴─────────┴──────────┘
↓
Unified response handler
↓
Domain event published
↓
Email notification triggered
↓
Success UI feedback
Domain-Driven Design at Scale
Enterprise Architecture
Testing Philosophy
Payment Integration Complexity
Founding Engineer Experience
Enterprise Mentorship Value
Scaling Challenges
Framework: Next.js + React + TypeScript
Architecture: Domain-Driven Design (50+ features)
Design System: Kamona UI (built on Tailwind CSS)
Testing: Jest (90% coverage) + Playwright (95% coverage)
CI/CD: Jenkins + Docker
Structure: Monorepo with feature-based domains
Payment SDKs: Apple Pay, Google Pay, TrueLayer, Checkout
Infrastructure: Docker containers, automated deployments
Email: Transactional email templates
Currency Engine: Global currency support (150+ currencies)
MonieWorld represented the full spectrum of frontend engineering challenges: building a fintech platform from the ground up as founding engineer, architecting for global currency scale, integrating multiple complex payment providers, and establishing enterprise-grade quality through comprehensive testing.
The technical achievements, 90% unit test coverage, 95% E2E coverage, 50+ features organized via DDD, and global currency support, demonstrate that frontend engineering at scale requires architectural rigor, not just UI implementation.
The 55% increase in payment success rates and 90% reduction in production bugs show that technical excellence directly drives business outcomes. The £100K+ processed in the first month validated that the architecture could handle real financial transactions at scale.
Working with an enterprise architect transformed my approach to software design. The DDD patterns, testing strategies, and architectural principles learned during this collaboration became the foundation not just for MonieWorld, but for how I approach complex engineering problems.
The currency architecture investment, designing a system that could scale to every currency in the world without code changes, exemplifies the difference between building for now versus building for scale. That upfront time investment enabled MonieWorld to expand to new markets with configuration changes, not rewrites.
As founding engineer, the patterns I established became organizational standards that outlasted my direct involvement. That’s the real measure of architectural success: building systems that enable others to ship features confidently, quickly, and correctly.
Send me an email or message me on LinkedIn if you're looking for someone who builds without BS.