A comprehensive charitable distribution and beneficiary management system built with NestJS. Wesal enables institutions to manage the allocation and delivery of aid coupons to beneficiaries, track distributions, and communicate with recipients at scale.
- Features
- Tech Stack
- Architecture Overview
- Prerequisites
- Getting Started
- Environment Variables
- API Documentation
- Modules
- Authentication & Security
- Caching Strategy
- Rate Limiting
- File Uploads
- Scripts
- Project Structure
- Multi-tenant institutions — each institution manages its own employees, beneficiaries, distributions, and posts
- Role-based access control — four employee roles (Admin, Distributer, Publisher, Deliverer) with fine-grained permissions
- Distribution lifecycle — manage campaigns through DRAFT → ACTIVE → COMPLETED → CANCELLED states
- Coupon allocation & delivery — allocate coupons per round, track delivery status per beneficiary
- Beneficiary management — register and filter beneficiaries by health status, housing status, income range, family size, and more
- Family member tracking — link spouses, children, and parents to each beneficiary
- Messaging system — create and send targeted notifications, alerts, and reminders to beneficiaries with delivery tracking
- Institution posts — publish announcements with image uploads and soft-delete support
- File uploads — profile images and post images with categorized disk storage
- JWT authentication — separate auth flows for institution employees and beneficiaries with refresh token rotation
- Redis caching — intelligent route-based TTL caching with version-based invalidation
- Rate limiting — global and per-route throttling to protect endpoints
- Swagger UI — interactive API documentation available out of the box
| Category | Technology |
|---|---|
| Framework | NestJS 11 / Express 5 |
| Language | TypeScript 5.8 |
| Database | PostgreSQL |
| ORM | Prisma 7.5 |
| Cache | Redis (cache-manager) |
| Auth | JWT + Passport, bcrypt |
| Validation | class-validator, class-transformer |
| File uploads | Multer |
| API Docs | Swagger / OpenAPI |
| Logging | Winston (nest-winston) |
| Rate limiting | @nestjs/throttler |
| Security | Helmet, CORS, CSRF protection |
| Build | SWC (fast transpiler) |
┌────────────────────────────────────────────────────────┐
│ Client / Frontend │
└────────────────────────────┬───────────────────────────┘
│ HTTP + Cookies
┌────────────────────────────▼───────────────────────────┐
│ NestJS API (Wesal) │
│ ┌──────────┐ ┌───────────┐ ┌──────────────────────┐ │
│ │ Auth │ │ Guards │ │ Interceptors │ │
│ │ JWT/CSRF │ │ RBAC/Rate │ │ Cache / Logger │ │
│ └──────────┘ └───────────┘ └──────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Modules: Institution · Employee · Beneficiary │ │
│ │ Distribution · Round · Coupon · Message │ │
│ │ Post · Family Member · Uploads │ │
│ └─────────────────────────────────────────────────┘ │
└──────────┬──────────────────────────┬──────────────────┘
│ │
┌──────▼──────┐ ┌───────▼──────┐
│ PostgreSQL │ │ Redis │
│ (Prisma) │ │ (Cache) │
└─────────────┘ └──────────────┘
- Node.js v18+
- PostgreSQL database
- Redis server
- npm or yarn
git clone https://github.com/your-username/wesal.git
cd wesalnpm installcp .env.example .envFill in the required values in .env (see Environment Variables).
npx prisma migrate deploy
npx prisma generatenpm run start:devThe API will be available at http://localhost:3000.
Swagger UI is available at http://localhost:3000/api/docs.
Create a .env file based on .env.example:
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/wesal
# JWT Secrets (64-byte hex strings)
JWT_SECRET=your_64_byte_hex_access_secret
JWT_REFRESH_SECRET=your_64_byte_hex_refresh_secret
# App
NODE_ENV=development
PORT=3000
SERVER_URL=http://localhost:3000
# CORS
CORS_ORIGIN=http://localhost:3000
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_TTL=300| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
Yes | — | PostgreSQL connection string |
JWT_SECRET |
Yes | — | Access token signing key (64-byte hex) |
JWT_REFRESH_SECRET |
Yes | — | Refresh token signing key (64-byte hex) |
NODE_ENV |
No | development |
development, production, or test |
PORT |
No | 3000 |
Server port |
SERVER_URL |
No | — | Public server URL |
CORS_ORIGIN |
No | http://localhost:3000 |
Allowed frontend origin |
REDIS_HOST |
No | localhost |
Redis server host |
REDIS_PORT |
No | 6379 |
Redis server port |
REDIS_TTL |
No | 300 |
Default cache TTL (seconds) |
Once the server is running, visit the Swagger UI at:
http://localhost:3000/api/docs
The API is organized into the following tag groups:
auth-institution— Institution employee authenticationauth-beneficiary— Beneficiary authenticationinstitutions— Institution managementemployees— Employee managementbeneficiaries— Beneficiary managementfamily-members— Family member managementdistributions— Distribution campaignsrounds— Distribution roundscoupons— Coupon templatesround-allocations— Coupon allocation and deliverymessages— Message creation and sendingmessage-deliveries— Delivery trackingposts— Institution posts and announcementsuploads— File upload endpoints
Handles JWT-based authentication for both institution employees and beneficiaries. Issues access tokens (15-minute expiry) and refresh tokens stored in HTTP-only cookies (7-day expiry). Includes CSRF protection on token refresh endpoints.
Institution registration, profile management, search, and statistics. Institutions are the top-level multi-tenant entity.
Manage institution staff members. Supports creating, updating, activating/deactivating employees, assigning roles, and changing passwords.
Employee Roles:
| Role | Capabilities |
|---|---|
ADMIN |
Full access to all institution resources |
DISTRIBUTER |
Manage distributions, rounds, coupons, and allocations |
PUBLISHER |
Create and manage institution posts |
DELIVERER |
Deliver coupons and view allocations |
Register and manage beneficiaries. Supports filtering by health status, housing status, income, and family size. Beneficiaries authenticate separately from employees.
Manage family members (spouse, child, parent) linked to each beneficiary with health status tracking.
Create and manage aid distribution campaigns. Linked to a coupon template and progresses through: DRAFT → ACTIVE → COMPLETED → CANCELLED.
Manage distribution rounds within a campaign. Each round tracks its own status and coupon allocation count.
Define reusable coupon templates with types: CASH, FOOD, SHOPPING, OTHER.
Allocate beneficiaries to a round, generate coupon codes, and track delivery status (PENDING, DELIVERED, MISSED) per beneficiary.
Create messages for beneficiaries with types: NOTIFICATION, ALERT, PROMOTION, REMINDER, UPDATE. Send to a specific list of beneficiaries or to all beneficiaries in a round.
Track individual delivery status per beneficiary: PENDING → SENT → DELIVERED → READ. Mark messages as read, retrieve unread counts, and handle delivery failures.
Institution announcements with multi-image support and soft-delete. Publicly visible.
Profile image and post image upload with categorized disk storage.
- Login returns a short-lived access token (15 min) in the response body.
- A long-lived refresh token (7 days) is set as an HTTP-only cookie.
- Use
POST /auth/institution/refresh(or/auth/beneficiary/refresh) with a valid CSRF token to obtain a new access token. - Logout clears the refresh token cookie.
- Helmet — HTTP security headers
- CORS — configurable origin, credentials enabled, 24-hour preflight cache
- CSRF protection — token validation on refresh endpoints
- bcrypt — password hashing
- HTTP-only cookies — refresh tokens never exposed to JavaScript
- Secure cookies — enabled automatically in production
Redis caching is applied via a custom CachingInterceptor with route-aware TTLs:
| Route Category | TTL | Reason |
|---|---|---|
| Message deliveries | 0s (no cache) | Real-time data |
| Round allocations | 30s | High-frequency reads |
| Messages, rounds | 1–2 min | Moderate freshness |
| Beneficiaries | 2 min | Moderate freshness |
| Coupons, distributions | 5 min | Relatively static |
| Institutions, posts | 10 min | Mostly static |
Cache keys are scoped per institution or per user. Write operations (POST, PUT, PATCH, DELETE) automatically bump a version counter to invalidate stale cache entries.
| Scope | Limit |
|---|---|
| Global | 100 requests / 60 seconds |
| Auth endpoints | 5 requests / 15 minutes |
Exceeding the limit returns a 429 Too Many Requests response with a message indicating how long to wait.
Uploaded files are stored on disk under categorized directories:
- Profile images:
uploads/profile/ - Post images:
uploads/posts/
Endpoints:
| Method | Path | Description |
|---|---|---|
POST |
/uploads/profile |
Upload profile image |
GET |
/uploads/profile |
Get authenticated user's profile image |
GET |
/uploads/profile/:id |
Get beneficiary's profile image |
DELETE |
/uploads/profile-image |
Delete authenticated user's profile image |
POST |
/uploads/post/:id |
Upload post images (multiple) |
GET |
/uploads/post/:id |
Get post images |
DELETE |
/uploads/post/:postId/image/:imageName |
Delete specific post image |
# Development
npm run start:dev # Start with hot-reload
npm run start:debug # Start with debug + hot-reload
# Production
npm run build # Generate Prisma client + compile TypeScript
npm run start:prod # Run compiled output
# Code quality
npm run lint # Lint and auto-fix
npm run format # Format with Prettier
# Testing
npm run test # Unit tests
npm run test:watch # Unit tests in watch mode
npm run test:cov # Unit tests with coverage report
npm run test:e2e # End-to-end testswesal/
├── src/
│ ├── main.ts # Entry point, Swagger & global middleware setup
│ ├── app.module.ts # Root module
│ ├── auth/ # Authentication (JWT, refresh, CSRF)
│ ├── institution/ # Institution management
│ ├── employee/ # Employee management & RBAC
│ ├── beneficiary/ # Beneficiary management
│ ├── family-member/ # Beneficiary family members
│ ├── distribution/ # Distribution campaigns
│ ├── round/ # Distribution rounds
│ ├── coupon/ # Coupon templates
│ ├── round-beneficiary/ # Coupon allocation & delivery
│ ├── message/ # Messages to beneficiaries
│ ├── message-delivery/ # Message delivery tracking
│ ├── post/ # Institution posts
│ ├── uploads/ # File upload handling
│ ├── prisma/ # Prisma database service
│ └── common/
│ ├── config/ # Environment validation
│ ├── decorators/ # Custom parameter decorators
│ ├── enums/ # Shared enums
│ ├── filters/ # Global exception filter
│ ├── guards/ # RBAC, CSRF, rate limiting guards
│ ├── interceptors/ # Caching & logger interceptors
│ └── logger/ # Winston logger configuration
├── prisma/
│ └── schema.prisma # Database schema
├── test/ # E2E tests
├── .env.example # Environment variable template
├── nest-cli.json
├── tsconfig.json
└── package.json
This project is licensed under the MIT License.