The backend is built with NestJS (v11) on Node.js + TypeScript, following a modular domain-driven architecture. It exposes a RESTful API consumed by the frontend and integrates directly with Stellar Soroban smart contracts.
| Layer | Technology |
|---|---|
| Framework | NestJS 11 |
| Language | TypeScript 5 |
| Database | PostgreSQL via TypeORM |
| Cache / Queue | Redis + BullMQ |
| Auth | JWT (access + refresh tokens), Passport |
| Blockchain | Stellar Soroban SDK |
| API Docs | Swagger / OpenAPI (/docs) |
| Notifications | Firebase (push), Nodemailer (email), Africa's Talking (SMS) |
src/
├── auth/ # JWT auth, sessions, MFA, permissions
├── donations/ # Donation intents, confirmations, pledges
├── blood-requests/ # Blood request lifecycle
├── blood-units/ # Blood unit tracking
├── inventory/ # Inventory management
├── orders/ # Order processing
├── dispatch/ # Dispatch assignments
├── riders/ # Rider management
├── hospitals/ # Hospital registry
├── organizations/ # Organization management
├── soroban/ # Stellar Soroban contract integration
├── blockchain/ # On-chain event indexing
├── escrow-governance/ # Escrow fund management
├── notifications/ # Multi-channel notifications
├── tracking/ # Real-time location tracking
├── reporting/ # Analytics and reports
├── common/ # Shared filters, guards, middleware
└── main.ts # Bootstrap entry point
http://localhost:3000/api/v1
All routes are prefixed with /api/v1, controlled by the API_PREFIX environment variable.
The API uses JWT Bearer tokens. Most endpoints require authentication; public routes are decorated with @Public().
1. Register
POST /api/v1/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"password": "SecurePassword123!",
"name": "John Doe",
"role": "donor"
}2. Login — receive tokens
POST /api/v1/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "SecurePassword123!"
}Response:
{
"access_token": "<jwt>",
"refresh_token": "<jwt>"
}3. Authenticated requests — attach Bearer token
GET /api/v1/blood-requests
Authorization: Bearer <access_token>4. Refresh token
POST /api/v1/auth/refresh
Content-Type: application/json
{ "refreshToken": "<refresh_token>" }5. Logout
POST /api/v1/auth/logout
Authorization: Bearer <access_token>- All request bodies are validated via
class-validatorDTOs. Invalid payloads return400with field-level errors. - Responses follow a consistent error shape:
{ "code": "AUTH_INVALID_CREDENTIALS", "message": "Invalid email or password", "statusCode": 401, "timestamp": "2024-03-27T04:30:44.473Z" } - A
X-Correlation-Idheader is attached to every response for request tracing. - Idempotent mutation endpoints accept an optional
Idempotency-Keyheader to prevent duplicate processing.
Requests are throttled per role using Redis-backed distributed rate limiting:
| Scope | Limit |
|---|---|
| Default | 30 req / min |
| Auth routes | 10 req / min |
| Forgot password | 5 req / min |
Exceeding the limit returns 429 Too Many Requests.
After JWT validation, a global PermissionsGuard enforces role-based access. Restricted endpoints use the @RequirePermissions() decorator:
@RequirePermissions(Permission.MANAGE_USERS)
@Patch('unlock')POST /api/v1/donations/intent → create payment intent (returns unsigned tx)
PATCH /api/v1/donations/:id/confirm → submit signed transaction hash on-chain
GET /api/v1/donations/my-donations → donor history (donations + pledges)
GET /api/v1/donations/:id → single donation detail
The SorobanModule wraps the Stellar SDK. On-chain events are indexed by SorobanIndexerService and stored in PostgreSQL for fast querying. Blockchain submissions go through:
POST /api/v1/blockchain/submit
GET /api/v1/blockchain/transaction/:id
GET /api/v1/blockchain/status
Real-time events (tracking, notifications) are served over Socket.io via @nestjs/websockets. Connections are authenticated using the same JWT strategy via WsAuthService.
# Install dependencies
npm install
# Development (watch mode)
npm run start:dev
# Production
npm run build
npm run start:prodCopy .env.example to .env and fill in the required values:
cp .env.example .envKey variables:
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USERNAME=postgres
DATABASE_PASSWORD=
DATABASE_NAME=
JWT_SECRET=
JWT_REFRESH_SECRET=
REDIS_HOST=localhost
REDIS_PORT=6379
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
SOROBAN_CONTRACT_ID=
SOROBAN_SECRET_KEY=
SOROBAN_NETWORK=testnetnpm run migration:run # apply pending migrations
npm run migration:revert # revert last migration
npm run migration:generate # generate migration from entity changes
synchronizeis only enabled indevelopmentandtestenvironments. Production always uses explicit migrations.
Interactive Swagger docs are available at:
http://localhost:3000/docs
npm run test # unit tests
npm run test:e2e # end-to-end tests
npm run test:cov # coverage report
npm run test:contracts # Soroban contract integration tests