Frontend application for the RemitWise remittance and financial planning platform.
This is a Next.js-based frontend skeleton that provides the UI structure for all RemitWise features. The application is built with:
- Next.js 14 - React framework with App Router
- TypeScript - Type safety
- Tailwind CSS - Utility-first styling
- Lucide React - Icon library
The frontend includes placeholder pages and components for:
- Dashboard - Overview of remittances, savings, bills, and insurance
- Send Money - Remittance sending interface with automatic split preview
- Smart Money Split - Configuration for automatic allocation
- Savings Goals - Goal-based savings tracking and management
- Bill Payments - Bill tracking, scheduling, and payment
- Micro-Insurance - Policy management and premium payments
- Family Wallets - Family member management with roles and spending limits
The application requires connection to a Soroban RPC node.
- Testnet:
https://soroban-testnet.stellar.org(Passphrase:Test SDF Network ; September 2015) - Mainnet:
https://soroban-rpc.stellar.org(Passphrase:Public Global Stellar Network ; September 2015)
- Node.js 18+
- npm or yarn
# Install dependencies
npm install
# Setup Database
# 1. Ensure you have `.env` file with `DATABASE_URL="file:./dev.db"`
# 2. Run initial Prisma migration
npx prisma migrate dev
# Run development server
npm run devOpen http://localhost:3000 in your browser.
# Build for production
npm run build
# Start production server
npm startThe project includes unit tests and integration tests for API routes.
# Run all tests (unit + integration)
npm test
# Run unit tests only
npm run test:unit
# Run integration tests only
npm run test:integration
# Run integration tests in watch mode
npm run test:integration:watch- Location:
tests/unit/ - Command:
npm run test:unit - Framework: Node.js built-in
testmodule
- Location:
tests/integration/ - Command:
npm run test:integration - Framework: Node.js
node:test+ direct route handler calls - Database: In-memory SQLite (fast, isolated)
- Speed: Sub-10 second execution
What's Tested:
GET /api/health- Health check (no auth required)POST /api/auth/nonce- Nonce generationPOST /api/auth/login- Authentication with signaturePOST /api/auth/logout- Session cleanupGET /api/split- Protected route with auth enforcement- Error handling (400, 401, 404 responses)
How They Work: Integration tests import route handlers directly and call them as functions with mock requests. No server startup overhead, fully deterministic.
Documentation: See docs/TESTING_INTEGRATION.md for detailed guide on writing and running integration tests.
Tests run on GitHub Actions for every push/PR to main and dev. The pipeline fails if any tests fail.
RemitWise implements a nonce-based challenge-response authentication mechanism to verify genuine wallet ownership over the Stellar network.
Message Format and Verification Steps:
- Request Nonce: The frontend calls
GET /api/auth/nonce?address=<STELLAR_PUBLIC_KEY>to receive a securely generated random 32-byte hex string (nonce). This nonce is temporarily cached on the server. - Sign Nonce: The client wallet (e.g., Freighter) is prompted to sign the raw nonce. The message to be signed is the byte representation of the hex nonce.
- Submit Signature: The client submits
{"address": "...", "signature": "..."}toPOST /api/auth/login. The signature should be base64-encoded. - Verification: The backend converts the nonce to a Buffer and verifies the base64 signature against the supplied public address using
@stellar/stellar-sdk(Keypair.fromPublicKey(address).verify(nonceBuffer, signatureBuffer)). Invalid signatures or missing/expired nonces will receive a401 Unauthorized.
To run the Playwright end-to-end tests for authentication and protected routes:
# Run tests
npm run test:e2eremitwise-frontend/
├── app/
│ ├── api/ # API routes
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page
│ ├── globals.css # Global styles
│ ├── dashboard/ # Dashboard page
│ ├── send/ # Send money page
│ ├── split/ # Money split configuration
│ ├── goals/ # Savings goals
│ ├── bills/ # Bill payments
│ ├── insurance/ # Insurance policies
│ └── family/ # Family wallets
├── components/ # Reusable components
├── lib/ # Utilities and helpers
│ └── auth.ts # Auth middleware
├── docs/ # Documentation
│ └── API_ROUTES.md # API routes documentation
├── public/ # Static assets
└── package.json
See API Routes Documentation for details on authentication and available endpoints.
Quick Reference:
- Public routes:
/api/health,/api/auth/* - Protected routes:
/api/user/*,/api/split,/api/goals,/api/bills,/api/insurance,/api/family,/api/send
-
Wallet Connection
- Integrate Freighter wallet or similar
- Connect to Stellar network (testnet/mainnet)
- Handle account authentication
-
Smart Contract Integration
- Connect to deployed Soroban contracts
- Implement contract function calls
- Handle transaction signing and submission
-
Anchor Platform Integration
- Integrate with anchor platform APIs for fiat on/off-ramps
- Handle deposit/withdrawal flows
- Process exchange rate quotes
- Environment Setup: Set
ANCHOR_API_BASE_URLin your.envfile (see.env.example). - Frontend API Endpoint: Use
GET /api/anchor/ratesto fetch cached exchange rates with fallback support.
-
Transaction Tracking
- Display on-chain transaction history
- Show transaction status and confirmations
- Implement real-time updates
- Send Money Page: Connect to Stellar SDK for transaction creation and signing
- Split Configuration: Call
remittance_splitcontract to initialize/update split - Savings Goals: Integrate with
savings_goalscontract for goal management - Bills: Connect to
bill_paymentscontract for bill tracking - Insurance: Integrate with
insurancecontract for policy management - Family Wallets: Connect to
family_walletcontract for member management
This Next.js application uses API routes to handle backend functionality. API routes are located in the app/api/ directory and follow Next.js 14 App Router conventions.
Key API Routes:
/api/auth/*- Authentication endpoints (wallet connect, nonce generation, signature verification)/api/transactions/*- Transaction history and status/api/contracts/*- Soroban smart contract interactions/api/health- Health check endpoint
All API routes are serverless functions deployed alongside the frontend.
Create a .env.local file in the root directory with the following variables:
# Stellar Network Configuration
NEXT_PUBLIC_STELLAR_NETWORK=testnet # or 'mainnet'
NEXT_PUBLIC_HORIZON_URL=https://horizon-testnet.stellar.org
NEXT_PUBLIC_SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
# Contract IDs (deployed Soroban contracts)
NEXT_PUBLIC_REMITTANCE_SPLIT_CONTRACT_ID=
NEXT_PUBLIC_SAVINGS_GOALS_CONTRACT_ID=
NEXT_PUBLIC_BILL_PAYMENTS_CONTRACT_ID=
NEXT_PUBLIC_INSURANCE_CONTRACT_ID=
NEXT_PUBLIC_FAMILY_WALLET_CONTRACT_ID=
# Authentication
AUTH_SECRET=your-secret-key-here # Generate with: openssl rand -base64 32
SESSION_COOKIE_NAME=remitwise-session
SESSION_MAX_AGE=86400 # 24 hours in seconds
# API Configuration
API_RATE_LIMIT=100 # requests per minute
API_TIMEOUT=30000 # milliseconds
# Optional: Anchor Platform
ANCHOR_PLATFORM_URL=
ANCHOR_PLATFORM_API_KEY=See .env.example for a complete list of configuration options.
The middleware (middleware.ts) applies CORS headers, security headers, and request validation to all /api routes.
Cross-Origin Resource Sharing (CORS) is configured to allow requests from the frontend application:
- Allowed Origins: Requests from
NEXT_PUBLIC_APP_URLare allowed (or same-origin) - Allowed Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
- Allowed Headers: Content-Type, Authorization, X-Requested-With
- Credentials: Allowed for same-origin requests
- Preflight Handling: OPTIONS requests return 204 No Content with appropriate CORS headers
Configuration:
Set NEXT_PUBLIC_APP_URL in .env.local:
# Frontend URL for CORS policy (e.g., http://localhost:3000)
NEXT_PUBLIC_APP_URL=http://localhost:3000Example: Testing CORS
# Test CORS headers on a preflight request
curl -i -X OPTIONS http://localhost:3000/api/health \
-H "Origin: http://localhost:3000" \
-H "Access-Control-Request-Method: POST"
# Response includes:
# Access-Control-Allow-Origin: http://localhost:3000
# Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
# Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-WithAll API responses include the following security headers to protect against common vulnerabilities:
| Header | Value | Purpose |
|---|---|---|
X-Content-Type-Options |
nosniff |
Prevents MIME-type sniffing attacks |
X-Frame-Options |
DENY |
Prevents clickjacking attacks |
X-XSS-Protection |
1; mode=block |
Legacy XSS protection (modern browsers ignore) |
Vary |
Origin |
Instructs caches to vary response by origin |
These headers are applied automatically to all /api responses and do not require configuration.
POST, PUT, and PATCH requests are validated for size to prevent oversized payloads:
- Default Limit: 1MB (1,048,576 bytes)
- Validation: Checks
Content-Lengthheader first, falls back to reading body if header missing - Response: 413 Payload Too Large with JSON error details if exceeded
Configuration:
# Maximum request body size in bytes (default 1MB)
API_MAX_BODY_SIZE=1048576Example: Testing Body Size Validation
# Valid request (under 1MB)
curl -i -X POST http://localhost:3000/api/test \
-H "Content-Type: application/json" \
-d '{"data":"test"}'
# Response: 200 OK or appropriate handler response
# Oversized request (over 1MB)
curl -i -X POST http://localhost:3000/api/test \
-H "Content-Type: application/json" \
-d "$(dd if=/dev/zero bs=1M count=2 2>/dev/null | base64)"
# Response: 413 Payload Too Large
# {"error": "Payload Too Large", "message": "Request body exceeds maximum size of 1048576 bytes."}The middleware processes requests in the following order:
- Whitelist Checks - Health check and Playwright test requests bypass all middleware
- CORS & Security Headers - Applied to all responses before processing
- Preflight Handling - OPTIONS requests return 204 No Content
- Body Size Validation - POST/PUT/PATCH requests checked against size limit
- Rate Limiting - Applied after headers/validation (does not block preflight)
- Response - Headers added to response, request proceeds to handler
This order ensures OPTIONS preflight requests complete successfully while maintaining security and rate limiting enforcement.
The backend API routes run automatically with the Next.js development server:
# Development mode (with hot reload)
npm run dev
# Production build
npm run build
npm startThe API will be available at http://localhost:3000/api/*
RemitWise uses wallet-based authentication with the following flow:
-
Wallet Connect: User connects their Stellar wallet (Freighter, Albedo, etc.)
- Frontend detects wallet extension
- User authorizes connection
- Public key is retrieved
-
Nonce Generation:
- Client requests nonce from
/api/auth/nonce - Server generates unique nonce and stores temporarily
- Nonce returned to client
- Client requests nonce from
-
Signature Verification:
- Client signs nonce with wallet private key
- Signed message sent to
/api/auth/verify - Server verifies signature matches public key
- If valid, session token is created
-
Session Management:
- JWT token stored in HTTP-only cookie
- Token includes user's public key and expiration
- Subsequent requests include token for authentication
- Token validated on protected API routes
Protected Routes: All /api/transactions/*, /api/contracts/* endpoints require valid session.
The application interacts with the following Soroban smart contracts on Stellar:
| Contract | Purpose | Environment Variable |
|---|---|---|
| Remittance Split | Automatic money allocation | NEXT_PUBLIC_REMITTANCE_SPLIT_CONTRACT_ID |
| Savings Goals | Goal-based savings management | NEXT_PUBLIC_SAVINGS_GOALS_CONTRACT_ID |
| Bill Payments | Bill tracking and payments | NEXT_PUBLIC_BILL_PAYMENTS_CONTRACT_ID |
| Insurance | Micro-insurance policies | NEXT_PUBLIC_INSURANCE_CONTRACT_ID |
| Family Wallet | Family member management | NEXT_PUBLIC_FAMILY_WALLET_CONTRACT_ID |
Deployment Notes:
- Contracts must be deployed to Stellar testnet/mainnet before use
- Update contract IDs in
.env.localafter deployment - Verify contract addresses match network (testnet vs mainnet)
- Contract ABIs are included in
lib/contracts/directory
Health Check Endpoint: GET /api/health
Returns system status and connectivity:
{
"status": "healthy",
"timestamp": "2024-02-24T10:30:00Z",
"services": {
"stellar": "connected",
"contracts": "available",
"database": "connected"
},
"version": "0.1.0"
}Monitoring Recommendations:
- Set up uptime monitoring for
/api/health - Monitor API response times and error rates
- Track Stellar network connectivity
- Log contract interaction failures
- Set alerts for authentication failures
Unit Tests
Test individual API route handlers and utility functions:
# Run unit tests
npm test
# Run with coverage
npm run test:coverage
# Watch mode
npm run test:watchUnit tests are located alongside source files with .test.ts extension.
Integration Tests
Test complete API flows including authentication and contract interactions:
# Run integration tests
npm run test:integration
# Test specific API route
npm run test:integration -- authIntegration tests are in the __tests__/integration/ directory.
Testing Checklist:
- ✓ Authentication flow (nonce → sign → verify)
- ✓ Contract interactions (all 5 contracts)
- ✓ Error handling and validation
- ✓ Rate limiting
- ✓ Session management
For detailed API specifications:
- OpenAPI Spec: See
openapi.yamlfor complete API documentation - Interactive Docs: Run
npm run docsto view Swagger UI athttp://localhost:3000/api-docs - Postman Collection: Import
postman_collection.jsonfor testing
Quick API Reference:
# Authentication
POST /api/auth/nonce # Get nonce for signing
POST /api/auth/verify # Verify signature and create session
POST /api/auth/logout # End session
# Transactions
GET /api/transactions # List user transactions
GET /api/transactions/:id # Get transaction details
# Contracts
POST /api/contracts/split # Initialize/update split configuration
POST /api/contracts/goals # Create/manage savings goals
POST /api/contracts/bills # Manage bill payments
POST /api/contracts/insurance # Manage insurance policies
POST /api/contracts/family # Manage family wallet
# System
GET /api/health # Health check- All forms are currently disabled (placeholders)
- UI uses a blue/indigo color scheme
- Responsive design with mobile-first approach
- Components are structured for easy integration
All list endpoints support standardized cursor-based pagination with the following parameters:
limit(optional): Maximum number of items to return (default: 20, max: 100)cursor(optional): Cursor for pagination (used to fetch the next page)
Response shape for all paginated endpoints:
{
"data": [...],
"nextCursor"?: "string",
"hasMore": boolean
}GET /api/goals: Get paginated list of savings goalsPOST /api/goals: Create a new savings goalGET /api/bills: Get paginated list of billsPOST /api/bills: Create a new billGET /api/remittance/history: Get paginated list of transaction historyPOST /api/remittance/history: Create a new transaction
- Real-time transaction updates
- Push notifications for bill reminders
- Charts and graphs for financial insights
- Multi-language support
- Dark mode
- Mobile app (React Native)
MIT
API Versioning
- Approach (decided): URL prefix versioning using
/api/v{n}/...(e.g./api/v1/...). This is simple to route, cache, and reason about in the frontend and server layers. - Current status: The existing API surface in this repository is labeled as v1. To avoid breaking existing clients, the app rewrites
/api/*to/api/v1/*at the Next.js layer so existing clients can continue using/api/...without changes. - Routes: When adding new server routes, prefer placing them under
app/api/v1/(orpages/api/v1/if using pages router) so they are clearly versioned. Optionally duplicate stable v1 routes under thev1namespace during a migration window rather than deleting the legacy route immediately. - How to introduce v2: Create a new
app/api/v2/namespace containing the new behavior. Update platform routes or API gateway rules to expose/api/v2/...and leave the rewrite in place so/api/*stays mapped to the last published stable version (v1) until you intentionally change it.
Deprecation Policy
- When a new major version (e.g. v2) is released, older major versions will be supported for a minimum of 6 months before scheduled removal. During that window:
- Maintain security fixes and critical bug fixes for the deprecated major version.
- Announce deprecation clearly in changelogs and developer docs with migration guides.
- Provide automated redirects or compatibility layers where feasible.
OpenAPI / API Documentation
- This repository contains an OpenAPI descriptor for the current v1 API at
openapi.yaml(root). Theserversentry points to the/api/v1base path. Updateopenapi.yamlas you add endpoints.
Rate Limiting
- All
/api/*routes are protected by a global rate limiter using in-memorylru-cache. - Limits (per IP/session):
- Auth endpoints (
/api/auth/*): 10 requests per minute - Write endpoints (
POST,PUT,DELETE,PATCH): 50 requests per minute - General read endpoints (
GET): 100 requests per minute
- Auth endpoints (
- Whitelisted routes:
/api/healthis exempt from rate limiting to ensure uptime monitoring is not blocked. - Behavior: When a limit is exceeded, the server responds with a
429 Too Many Requestsstatus code and aRetry-Afterheader indicating the number of seconds until the rate limit resets. Rate limit information is also provided in the response headers (X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset).
Non-breaking guarantee
- To meet the repository's backward-compatibility requirement, we keep
/api/*behavior unchanged by rewriting it to/api/v1/*. This preserves compatibility for existing consumers.
If you want, I can also:
- Move or duplicate any existing API route files into an explicit
app/api/v1/folder. - Expand
openapi.yamlwith concrete endpoint definitions from your backend contract or tests.
API Endpoints (v1)
-
POST /api/bills— Create bill transaction XDR- Request headers:
x-user(caller public key) - Body:
{ name, amount, dueDate, recurring, frequencyDays } - Validations:
amount > 0,dueDatevalid ISO date, whenrecurring === truethenfrequencyDays > 0. - Response:
{ xdr: string }— unsigned transaction XDR ready for the frontend to sign and submit.
- Request headers:
-
POST /api/bills/[id]/pay— Build pay-bill transaction XDR- Request headers:
x-user(caller public key) - Response:
{ xdr: string }
- Request headers:
-
POST /api/bills/[id]/cancel— Build cancel-bill transaction XDR- Request headers:
x-user(caller public key) - Optional owner-only enforcement: set header
x-owner-only: 1andx-ownerto require the caller match the owner. - Response:
{ xdr: string }
- Request headers:
Notes:
- These endpoints return a transaction XDR composed of
manageDataoperations that encode the requested action. The frontend should sign the returned XDR and submit it to Horizon (or via a backend submission endpoint) to complete the operation. - Server builds transactions using the Horizon URL in
HORIZON_URLand network passphrase inNETWORK_PASSPHRASE(defaults to testnet). Set these environment variables in production to use a different network.
Insurance endpoints (v1)
-
POST /api/insurance— Create policy transaction XDR- Request headers:
x-user(caller public key) - Body:
{ name, coverageType, monthlyPremium, coverageAmount } - Validations:
monthlyPremium > 0,coverageAmount > 0, requirednameandcoverageType. - Response:
{ xdr: string }— unsigned transaction XDR ready for the frontend to sign and submit.
- Request headers:
-
POST /api/insurance/[id]/pay— Build pay-premium transaction XDR- Request headers:
x-user(caller public key) - Response:
{ xdr: string }
- Request headers:
-
POST /api/insurance/[id]/deactivate— Build deactivate-policy transaction XDR- Request headers:
x-user(caller public key) - Optional owner-only enforcement: set header
x-owner-only: 1andx-ownerto require the caller match the owner. - Response:
{ xdr: string }
- Request headers:
Notes:
- These endpoints return transaction XDRs composed with
manageDataoperations to encode policy actions. If you prefer Soroban contract invocations, I can convert the builders to use contract calls.
RemitWise exposes an OpenAPI discovery endpoint:
/api/.well-known/openapi
This allows integrators and wallets to automatically discover the RemitWise API specification.