Skip to content

Commit 807d71e

Browse files
authored
Merge pull request #375 from Ayinkx1/main
Add SMS messaging microservice
2 parents 3cd866f + 7a0fb37 commit 807d71e

32 files changed

Lines changed: 11936 additions & 0 deletions
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
NODE_ENV=development
2+
SERVICE_PORT=3010
3+
4+
DB_HOST=localhost
5+
DB_PORT=5432
6+
DB_USER=postgres
7+
DB_PASSWORD=postgres
8+
DB_NAME=sms_service
9+
DB_SYNCHRONIZE=true
10+
11+
SMS_PROVIDER=console
12+
SMS_DEFAULT_FROM=Quest
13+
14+
TWILIO_ACCOUNT_SID=
15+
TWILIO_AUTH_TOKEN=
16+
TWILIO_FROM_NUMBER=
17+
TWILIO_STATUS_CALLBACK_URL=
18+
19+
AWS_REGION=us-east-1
20+
AWS_SNS_SENDER_ID=Quest
21+
22+
OTP_TTL_SECONDS=300
23+
OTP_LENGTH=6
24+
SMS_RATE_LIMIT_MAX=5
25+
SMS_RATE_LIMIT_WINDOW_SECONDS=60
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# SMS Service
2+
3+
NestJS microservice for sending verification codes, alerts, and time-sensitive text messages.
4+
5+
## Features
6+
7+
- SMS, message, and delivery receipt entities backed by TypeORM/PostgreSQL
8+
- Provider abstraction with local console sending and Twilio HTTP support
9+
- Secure OTP generation with hashed verification codes and expiry
10+
- Handlebars message templates
11+
- Scheduled message dispatch through `@nestjs/schedule`
12+
- Delivery receipt webhook endpoint
13+
- Phone validation, per-phone rate limiting, history, and analytics
14+
- Docker and docker-compose configuration
15+
16+
## Local Run
17+
18+
```bash
19+
cd microservices/sms-service
20+
npm install
21+
npm run start:dev
22+
```
23+
24+
The default `SMS_PROVIDER=console` logs outbound SMS messages and marks them sent. Set `SMS_PROVIDER=twilio` with `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, and `TWILIO_FROM_NUMBER` to send real SMS.
25+
26+
## API
27+
28+
- `GET /health`
29+
- `POST /sms/send`
30+
- `POST /sms/send-template`
31+
- `POST /sms/otp`
32+
- `POST /sms/otp/verify`
33+
- `POST /sms/receipts`
34+
- `GET /sms`
35+
- `GET /sms/:id`
36+
- `POST /sms/:id/cancel`
37+
- `GET /sms-analytics`
38+
- `GET /sms-templates`
39+
40+
## Docker
41+
42+
```bash
43+
cd microservices/sms-service
44+
docker compose -f docker/docker-compose.yml up --build
45+
```
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
FROM node:18-alpine AS builder
2+
3+
WORKDIR /app
4+
5+
COPY package*.json ./
6+
COPY tsconfig*.json ./
7+
COPY nest-cli.json ./
8+
9+
RUN npm ci
10+
11+
COPY src ./src
12+
RUN npm run build
13+
14+
FROM node:18-alpine
15+
16+
WORKDIR /app
17+
18+
RUN apk add --no-cache dumb-init
19+
20+
COPY package*.json ./
21+
RUN npm ci --only=production && npm cache clean --force
22+
23+
COPY --from=builder /app/dist ./dist
24+
25+
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
26+
USER nodejs
27+
28+
EXPOSE 3010
29+
30+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
31+
CMD wget --no-verbose --tries=1 --spider http://localhost:3010/health || exit 1
32+
33+
ENTRYPOINT ["dumb-init", "--"]
34+
CMD ["node", "dist/main.js"]
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
version: '3.8'
2+
3+
services:
4+
sms-service:
5+
container_name: sms-service
6+
build:
7+
context: ..
8+
dockerfile: docker/Dockerfile
9+
ports:
10+
- '3010:3010'
11+
environment:
12+
- NODE_ENV=development
13+
- SERVICE_PORT=3010
14+
- DB_HOST=postgres
15+
- DB_PORT=5432
16+
- DB_USER=${DB_USER:-postgres}
17+
- DB_PASSWORD=${DB_PASSWORD:-postgres}
18+
- DB_NAME=${DB_NAME:-sms_service}
19+
- SMS_PROVIDER=${SMS_PROVIDER:-console}
20+
- SMS_DEFAULT_FROM=${SMS_DEFAULT_FROM:-Quest}
21+
- TWILIO_ACCOUNT_SID=${TWILIO_ACCOUNT_SID:-}
22+
- TWILIO_AUTH_TOKEN=${TWILIO_AUTH_TOKEN:-}
23+
- TWILIO_FROM_NUMBER=${TWILIO_FROM_NUMBER:-}
24+
- TWILIO_STATUS_CALLBACK_URL=${TWILIO_STATUS_CALLBACK_URL:-}
25+
- OTP_TTL_SECONDS=${OTP_TTL_SECONDS:-300}
26+
- OTP_LENGTH=${OTP_LENGTH:-6}
27+
- SMS_RATE_LIMIT_MAX=${SMS_RATE_LIMIT_MAX:-5}
28+
- SMS_RATE_LIMIT_WINDOW_SECONDS=${SMS_RATE_LIMIT_WINDOW_SECONDS:-60}
29+
depends_on:
30+
postgres:
31+
condition: service_healthy
32+
networks:
33+
- sms-network
34+
restart: unless-stopped
35+
36+
postgres:
37+
container_name: postgres-sms
38+
image: postgres:15-alpine
39+
environment:
40+
- POSTGRES_USER=${DB_USER:-postgres}
41+
- POSTGRES_PASSWORD=${DB_PASSWORD:-postgres}
42+
- POSTGRES_DB=sms_service
43+
ports:
44+
- '5440:5432'
45+
volumes:
46+
- postgres_sms_data:/var/lib/postgresql/data
47+
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
48+
networks:
49+
- sms-network
50+
healthcheck:
51+
test: ["CMD-SHELL", "pg_isready -U postgres"]
52+
interval: 10s
53+
timeout: 5s
54+
retries: 5
55+
restart: unless-stopped
56+
57+
volumes:
58+
postgres_sms_data:
59+
driver: local
60+
61+
networks:
62+
sms-network:
63+
driver: bridge
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import js from '@eslint/js';
2+
import tsParser from '@typescript-eslint/parser';
3+
import tsPlugin from '@typescript-eslint/eslint-plugin';
4+
import prettierPlugin from 'eslint-plugin-prettier';
5+
import configPrettier from 'eslint-config-prettier';
6+
7+
export default [
8+
js.configs.recommended,
9+
{
10+
files: ['**/*.ts'],
11+
languageOptions: {
12+
parser: tsParser,
13+
parserOptions: {
14+
project: './tsconfig.json',
15+
tsconfigRootDir: import.meta.dirname,
16+
sourceType: 'module',
17+
},
18+
globals: {
19+
console: 'readonly',
20+
process: 'readonly',
21+
Buffer: 'readonly',
22+
fetch: 'readonly',
23+
describe: 'readonly',
24+
beforeEach: 'readonly',
25+
it: 'readonly',
26+
expect: 'readonly',
27+
jest: 'readonly',
28+
},
29+
},
30+
plugins: {
31+
'@typescript-eslint': tsPlugin,
32+
prettier: prettierPlugin,
33+
},
34+
rules: {
35+
...tsPlugin.configs.recommended.rules,
36+
'prettier/prettier': 'error',
37+
'@typescript-eslint/no-explicit-any': 'off',
38+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
39+
},
40+
},
41+
configPrettier,
42+
];
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "https://json.schemastore.org/nest-cli",
3+
"collection": "@nestjs/schematics",
4+
"sourceRoot": "src",
5+
"compilerOptions": {
6+
"deleteOutDir": true
7+
}
8+
}

0 commit comments

Comments
 (0)