Skip to content

LabsCrypt/remitlend-backend

Repository files navigation

RemitLend Backend API

Express.js backend service for the RemitLend platform, providing API endpoints for credit scoring, remittance simulation, and NFT metadata management.

Overview

The backend serves as a bridge between the frontend application and the Stellar blockchain, handling:

  • Loan Event Indexing: A robust polling service that watches Soroban RPC for LoanRequested, LoanApproved, and LoanRepaid events.
  • Credit Scoring: Generation and verification of borrower scores based on indexed history.
  • Remittance Simulation: API support for generating mocked remittance data for testing.
  • NFT Metadata: Serving metadata for the Remittance NFT collection.
  • Security: Request validation, rate limiting, and centralized error handling.

Tech Stack

  • Runtime: Node.js 18+
  • Framework: Express.js 5
  • Language: TypeScript
  • Validation: Zod
  • Testing: Jest + Supertest
  • Documentation: Swagger/OpenAPI
  • Code Quality: ESLint + Prettier

Getting Started

Prerequisites

  • Node.js 18 or higher
  • npm or yarn

Installation

# Install dependencies
npm install

# Copy environment variables
cp .env.example .env

# Apply database migrations (requires PostgreSQL and DATABASE_URL in .env)
npm run migrate:up

# Start development server
npm run dev

Database and migrations

The API expects a PostgreSQL database. Set DATABASE_URL in .env (see .env.example).

Apply schema migrations from the backend directory:

npm run migrate:up

Rollback last batch (when needed):

npm run migrate:down

Scripts use migrate:up and migrate:down (colon-separated names), which work reliably across shells and CI.

Core tables are created by these migrations (run in filename order):

Migration Tables
1771691269865_initial-schema.js scores, remittance_history
1771691269866_loan-events-schema.js loan_events, indexer_state
1772000000000_webhook-subscriptions.js webhook_subscriptions
1773000000001_user-profiles.js user_profiles
1773000000002_loan-history.js loan_history
1773000000003_indexed-events.js indexed_events
1774000000004_scores-add-created-at.js adds created_at to scores (idempotent)
1777000000007_unique-loan-status-events.js dedupes and enforces unique status events per loan

With Docker Compose from the repo root, the backend service runs migrate:up before npm run dev so the schema is applied automatically when the database is healthy.

Environment Variables

Create a .env file in the backend directory:

# Server Configuration
PORT=3001

# CORS Configuration
FRONTEND_URL=http://localhost:3000
# Optional backward-compatible fallback for multiple allowed origins during migration
# CORS_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3001

# Stellar Configuration
STELLAR_NETWORK=testnet
STELLAR_RPC_URL=https://soroban-testnet.stellar.org
STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
LOAN_MANAGER_CONTRACT_ID=
LOAN_MANAGER_ADMIN_SECRET=

# Future: Add API keys for remittance services
# WISE_API_KEY=your_key_here
# WESTERN_UNION_API_KEY=your_key_here

Available Scripts

# Development
npm run dev          # Start dev server with hot reload

# Database
npm run migrate:up   # Apply migrations (requires DATABASE_URL)
npm run migrate:down # Roll back last migration batch
npm run seed         # Seed realistic local development data
npm run seed:reset   # Reset and reseed development data

# Production
npm run build        # Compile TypeScript to JavaScript
npm start            # Run production build

# Testing
npm test             # Run test suite
npm test -- --watch  # Run tests in watch mode
npm test -- --coverage  # Run tests with coverage

# Code Quality
npm run lint         # Check code quality
npm run lint:fix     # Fix linting issues
npm run format       # Format code with Prettier
npm run format:check # Check code formatting

Development seed data

New contributors can populate a realistic local dataset after running migrations:

npm run seed

This seeds:

  • user_profiles with sample borrowers and a lender
  • scores with varied borrower scores
  • remittance_history with completed, late, missed, and pending records
  • loan_history with pending, active, repaid, and defaulted loans
  • loan_events so borrower dashboards, loan details, pool stats, and SSE endpoints have data
  • notifications with both read and unread sample messages
  • indexer_state so interest calculations have a seeded latest ledger

To wipe those local development rows and recreate them from scratch:

npm run seed:reset

API Endpoints

Health Check

GET /api/health

Check if the API is running.

Response:

{
  "status": "ok",
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Credit Score

GET /api/score/:userId

Get the credit score for a specific user based on their remittance history.

Parameters:

  • userId (string) - User identifier

Response:

{
  "userId": "user123",
  "score": 750,
  "history": {
    "totalTransactions": 24,
    "averageAmount": 500,
    "consistency": 0.95
  },
  "calculatedAt": "2024-01-15T10:30:00.000Z"
}

Error Responses:

  • 400 - Invalid user ID
  • 404 - User not found
  • 500 - Server error

Simulate Remittance

POST /api/score/simulate

Simulate remittance history for testing purposes.

Request Body:

{
  "userId": "user123",
  "transactions": [
    {
      "amount": 500,
      "date": "2024-01-01",
      "recipient": "family_member"
    }
  ]
}

Response:

{
  "userId": "user123",
  "score": 750,
  "simulationId": "sim_abc123"
}

API Documentation

Interactive API documentation is available via Swagger UI when the server is running:

URL: http://localhost:3001/api-docs

The Swagger documentation provides:

  • Complete endpoint specifications
  • Request/response schemas
  • Interactive API testing
  • Authentication details (when implemented)

Project Structure

backend/
├── src/
│   ├── __tests__/           # Test files
│   │   ├── health.test.ts
│   │   ├── score.test.ts
│   │   ├── validation.test.ts
│   │   └── errorHandling.test.ts
│   ├── config/              # Configuration files
│   │   └── swagger.ts       # Swagger/OpenAPI config
│   ├── controllers/         # Request handlers
│   │   ├── scoreController.ts
│   │   └── simulationController.ts
│   ├── middleware/          # Express middleware
│   │   ├── asyncHandler.ts  # Async error wrapper
│   │   ├── auth.ts          # Authentication (planned)
│   │   ├── errorHandler.ts  # Error handling
│   │   ├── rateLimiter.ts   # Rate limiting
│   │   └── validation.ts    # Request validation
│   ├── routes/              # API routes
│   │   └── index.ts
│   ├── schemas/             # Zod validation schemas
│   │   ├── scoreSchemas.ts
│   │   └── simulationSchemas.ts
│   ├── errors/              # Custom error classes
│   │   └── AppError.ts
│   ├── app.ts               # Express app setup
│   └── index.ts             # Server entry point
├── .env.example             # Environment template
├── .eslintrc.cjs            # ESLint configuration
├── .prettierrc              # Prettier configuration
├── jest.config.js           # Jest configuration
├── tsconfig.json            # TypeScript configuration
├── package.json
└── README.md

Middleware

Error Handler

Centralized error handling middleware that catches and formats errors.

import { errorHandler } from "./middleware/errorHandler";
app.use(errorHandler);

Validation

Request validation using Zod schemas.

import { validate } from "./middleware/validation";
import { mySchema } from "./schemas/mySchemas";

router.post("/endpoint", validate(mySchema), controller);

Rate Limiter

Protects endpoints from abuse with configurable rate limits.

import { rateLimiter } from "./middleware/rateLimiter";
app.use("/api/", rateLimiter);

Async Handler

Wraps async route handlers to catch errors automatically.

import { asyncHandler } from "./middleware/asyncHandler";

router.get(
  "/endpoint",
  asyncHandler(async (req, res) => {
    // Async code here
  }),
);

Testing

Running Tests

# Run all tests
npm test

# Run specific test file
npm test -- health.test.ts

# Run with coverage
npm test -- --coverage

# Watch mode
npm test -- --watch

Test Structure

import request from "supertest";
import app from "../app";

describe("GET /api/health", () => {
  it("should return 200 OK", async () => {
    const response = await request(app).get("/api/health").expect(200);

    expect(response.body).toHaveProperty("status", "ok");
  });
});

Test Coverage

Aim for >80% code coverage on new code. Current coverage:

  • Statements: Check with npm test -- --coverage
  • Branches: Check with npm test -- --coverage
  • Functions: Check with npm test -- --coverage
  • Lines: Check with npm test -- --coverage

Error Handling

Custom Error Class

import { AppError } from "./errors/AppError";

throw new AppError("User not found", 404);

Error Response Format

{
  "success": false,
  "message": "Error message",
  "statusCode": 400,
  "errors": []
}

Validation Schemas

Validation schemas are defined using Zod in the schemas/ directory.

Example Schema

import { z } from "zod";

export const getUserScoreSchema = z.object({
  params: z.object({
    userId: z.string().min(1, "User ID is required"),
  }),
});

export const simulateRemittanceSchema = z.object({
  body: z.object({
    userId: z.string().min(1),
    transactions: z.array(
      z.object({
        amount: z.number().positive(),
        date: z.string(),
        recipient: z.string(),
      }),
    ),
  }),
});

Future Enhancements

Phase 1: Real Remittance Integration

  • Wise API integration
  • Western Union API integration
  • Remittance data verification
  • Historical data import

Phase 2: Enhanced Features

  • User authentication (JWT)
  • Database integration (PostgreSQL)
  • IPFS integration for NFT metadata
  • Webhook support for blockchain events

Phase 3: Production Ready

  • Caching layer (Redis)
  • Logging and monitoring
  • CI/CD pipeline
  • Load balancing support
  • API versioning

Deployment

Docker

# Build image
docker build -t remitlend-backend .

# Run container
docker run -p 3001:3001 --env-file .env remitlend-backend

Docker Compose

From the project root:

docker compose up backend

Production Considerations

  • Set NODE_ENV=production
  • Use process manager (PM2, systemd)
  • Enable HTTPS
  • Configure proper CORS origins
  • Set up monitoring and logging
  • Implement health checks
  • Use environment-specific configs

Contributing

See CONTRIBUTING.md for guidelines on contributing to the backend.

Code Style

  • Follow TypeScript best practices
  • Use async/await over callbacks
  • Maintain strict typing
  • Write descriptive variable names
  • Add JSDoc comments for public functions
  • Keep functions small and focused

Before Submitting PR

# Run all checks
npm run lint
npm run format:check
npm test
npm run build

Troubleshooting

Port Already in Use

# Find and kill process on port 3001
lsof -ti:3001 | xargs kill -9

TypeScript Errors

# Clean build
rm -rf dist/
npm run build

Module Not Found

# Reinstall dependencies
rm -rf node_modules package-lock.json
npm install

License

ISC License - See LICENSE file for details.

Support

  • Open an issue for bug reports
  • Check existing issues before creating new ones
  • Provide detailed reproduction steps
  • Include error messages and logs

About

Remitlend: remitlend-backend component

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors