This project is a NestJS-based API that allows users to buy insurance plans and activate policies.
Create a .env
file in the root directory with the following variables:
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=postgres
POSTGRES_PASSWORD=your_password
POSTGRES_DB=insuretech_db
PORT=3000
This project uses PostgreSQL as its database. Make sure you have PostgreSQL installed and running on your system.
- Create a new PostgreSQL database with the name specified in your environment variables (
POSTGRES_DB
). - The application will automatically create the necessary tables when it first runs, thanks to TypeORM's synchronization feature.
The project includes a seeder that creates default users with wallets and insurance products:
-
Users: Two default users are created with wallets:
- John Doe ([email protected]) with 10,000 NGN (1,000,000 Kobo)
- Jane Smith ([email protected]) with 20,000 NGN (2,000,000 Kobo)
-
Products: Four default insurance products are created:
- Optimal care mini (Health) - 10,000 NGN (1,000,000 Kobo)
- Optimal care standard (Health) - 20,000 NGN (2,000,000 Kobo)
- Third-party Auto Insurance - 5,000 NGN (500,000 Kobo)
- Comprehensive Auto Insurance - 15,000 NGN (1,500,000 Kobo)
npm install
# or
yarn install
Development mode:
npm run start:dev
# or
yarn start:dev
npm run seed
# or
yarn seed
The application uses TypeORM's synchronize: true
setting, which means database tables are automatically created/altered based on entity definitions. In production, this should be set to false
and proper migrations should be used.
As per the requirements, this API does not implement authentication. Instead, it uses a userId
query parameter to identify users when required.
The seeder creates two default users:
-
John Doe
- ID: 1
- Email: [email protected]
- Wallet: 10,000 NGN (1,000,000 Kobo)
-
Jane Smith
- ID: 2
- Email: [email protected]
- Wallet: 20,000 NGN (2,000,000 Kobo)
Note: Wallet values are stored in Kobo (100 Kobo = 1 Naira)
All endpoints are prefixed with /api/v1
.
GET /api/v1/products
Query Parameters:
category
(optional): Filter by product category (HEALTH, AUTO, etc.)minPrice
(optional): Minimum price in NGNmaxPrice
(optional): Maximum price in NGN
Response:
{
"message": "Successfully retrieved products",
"result": [
{
"id": 1,
"name": "Optimal care mini",
"description": "",
"price": 10000,
"currency": "NGN",
"category": "HEALTH",
"createdAt": "2023-08-01T10:00:00.000Z",
"updatedAt": "2023-08-01T10:00:00.000Z"
},
// ...more products
]
}
GET /api/v1/products/:id
Response:
{
"message": "Product successfully retrieved",
"result": {
"id": 1,
"name": "Optimal care mini",
"description": "",
"price": 10000,
"currency": "NGN",
"category": "HEALTH",
"createdAt": "2023-08-01T10:00:00.000Z",
"updatedAt": "2023-08-01T10:00:00.000Z"
}
}
POST /api/v1/plans
Query Parameters:
userId
(required): ID of the user purchasing the plan
Request Body:
{
"productId": 1,
"quantity": 1
}
Response:
{
"message": "Plan created successfully",
"result": {
"id": 1,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"quantity": 1,
"product": {
"id": 1,
"createdAt": "2025-06-08T16:47:13.242Z",
"updatedAt": "2025-06-08T16:47:13.242Z",
"category": "health",
"name": "Optimal care mini",
"price": "10000.00",
"description": "",
"currency": "NGN",
"priceKobo": 1000000
},
"user": {
"id": 1,
"createdAt": "2025-06-08T16:47:13.225Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"wallet": 0
},
"pendingPolicies": [
{
"id": 1,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"status": "unused"
}
],
"totalPrice": "10000.00",
"totalPriceKobo": 1000000
}
}
GET /api/v1/plans
Query Parameters:
userId
(required): ID of the user
Response:
{
"message": "Plans fetched successfully",
"result": [
{
"id": 7,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"quantity": 1,
"product": {
"id": 13,
"createdAt": "2025-06-08T16:47:13.242Z",
"updatedAt": "2025-06-08T16:47:13.242Z",
"category": "health",
"name": "Optimal care mini",
"price": "10000.00",
"description": "",
"currency": "NGN",
"priceKobo": 1000000
},
"user": {
"id": 5,
"createdAt": "2025-06-08T16:47:13.225Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"wallet": 0
},
"pendingPolicies": [
{
"id": 7,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"status": "unused"
}
],
"totalPrice": "10000.00",
"totalPriceKobo": 1000000
}
// ..more plans
]
}
GET /api/v1/plans/:id
Query Parameters:
userId
(required): ID of the user
Response:
{
"message": "Plan retrieved successfully",
"result": {
"id": 1,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"quantity": 1,
"product": {
"id": 1,
"createdAt": "2025-06-08T16:47:13.242Z",
"updatedAt": "2025-06-08T16:47:13.242Z",
"category": "health",
"name": "Optimal care mini",
"price": "10000.00",
"description": "",
"currency": "NGN",
"priceKobo": 1000000
},
"user": {
"id": 1,
"createdAt": "2025-06-08T16:47:13.225Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"wallet": 0
},
"pendingPolicies": [
{
"id": 1,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"status": "unused"
}
],
"totalPrice": "10000.00",
"totalPriceKobo": 1000000
}
}
GET /api/v1/pending-policies
Query Parameters:
userId
(required): ID of the user
Response:
{
"message": "Pending policies fetched successfully",
"result": [
{
"id": 1,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"status": "unused",
"plan": {
"id": 7,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"quantity": 1,
"product": {
"id": 13,
"createdAt": "2025-06-08T16:47:13.242Z",
"updatedAt": "2025-06-08T16:47:13.242Z",
"category": "health",
"name": "Optimal care mini",
"price": 1000000,
"description": "",
"currency": "NGN"
},
"user": {
"id": 5,
"createdAt": "2025-06-08T16:47:13.225Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"wallet": 0
}
}
}
]
}
GET /api/v1/pending-policies/:id
Query Parameters:
userId
(required): ID of the user
Response:
{
"message": "Pending policy fetched successfully",
"result": {
"id": 7,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"status": "unused",
"plan": {
"id": 7,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"quantity": 1,
"product": {
"id": 13,
"createdAt": "2025-06-08T16:47:13.242Z",
"updatedAt": "2025-06-08T16:47:13.242Z",
"category": "health",
"name": "Optimal care mini",
"price": 1000000,
"description": "",
"currency": "NGN"
},
"user": {
"id": 5,
"createdAt": "2025-06-08T16:47:13.225Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"wallet": 0
}
},
"product": {
"id": 13,
"createdAt": "2025-06-08T16:47:13.242Z",
"updatedAt": "2025-06-08T16:47:13.242Z",
"category": "health",
"name": "Optimal care mini",
"price": 1000000,
"description": "",
"currency": "NGN"
}
}
}
POST /api/v1/pending-policies/:id/activate
Query Parameters:
userId
(required): ID of the user
Request Body:
{
"beneficiaryEmail": "[email protected]"
}
Response:
{
"message": "Pending policy activated successfully",
"result": {
"id": 4,
"createdAt": "2025-06-08T17:00:12.089Z",
"updatedAt": "2025-06-08T17:00:12.089Z",
"beneficiaryEmail": "[email protected]",
"product": {
"id": 13,
"createdAt": "2025-06-08T16:47:13.242Z",
"updatedAt": "2025-06-08T16:47:13.242Z",
"category": "health",
"name": "Optimal care mini",
"price": 1000000,
"description": "",
"currency": "NGN"
},
"user": {
"id": 5,
"createdAt": "2025-06-08T16:47:13.225Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"wallet": 0
},
"pendingPolicy": {
"id": 7,
"createdAt": "2025-06-08T16:56:29.902Z",
"updatedAt": "2025-06-08T17:00:12.089Z",
"status": "used"
}
}
}
GET /api/v1/policies
Query Parameters:
userId
(required): ID of the userbeneficiaryEmail
(optional | Boolean): Filter by beneficiary emailmine
(optional | Boolean): Filter by user that created the policy
Response:
{
"message": "Policies fetched successfully",
"policies": [
{
"id": 4,
"createdAt": "2025-06-08T17:00:12.089Z",
"updatedAt": "2025-06-08T17:00:12.089Z",
"beneficiaryEmail": "[email protected]",
"product": {
"id": 1,
"createdAt": "2025-06-08T16:47:13.242Z",
"updatedAt": "2025-06-08T16:47:13.242Z",
"category": "health",
"name": "Optimal care mini",
"price": 1000000,
"description": "",
"currency": "NGN"
},
"user": {
"id": 1,
"createdAt": "2025-06-08T16:47:13.225Z",
"updatedAt": "2025-06-08T16:56:29.902Z",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"wallet": 0
}
}
]
}
GET /api/v1/policies/:id
Query Parameters:
userId
(required): ID of the user
Response:
{
"message": "Policy fetched successfully",
"policy": {
"id": 1,
"startDate": "2023-08-01T00:00:00.000Z",
"endDate": "2024-08-01T00:00:00.000Z",
"planId": 1,
"pendingPolicyId": 1,
"userId": 1,
"createdAt": "2023-08-01T10:00:00.000Z",
"updatedAt": "2023-08-01T10:00:00.000Z"
}
}
- The wallet is deducted based on the product price × quantity when purchasing a plan.
- One beneficiary can have only one policy per product.
- The API follows a workflow where:
- User purchases a plan
- A pending policy is automatically created
- User activates the pending policy to create an active policy
- User purchases a Product by creating a Plan
- A Plan automatically creates a Pending Policy
- User activates a Pending Policy to create an Policy
All monetary values in the API are stored in Kobo (100 Kobo = 1 Naira) for precision, but are displayed in Naira in the API responses.