Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4da24e7
created skeleton flow
Dunsin-cyber Aug 14, 2025
20d5b03
added api documantation
Dunsin-cyber Aug 15, 2025
12dce25
add JWT
Dunsin-cyber Aug 15, 2025
0d132a8
feat: signup and login complete
Dunsin-cyber Aug 15, 2025
99ad67b
add new migration, middleware, controllers and serices
Dunsin-cyber Aug 15, 2025
15acc49
chore: api docs
Dunsin-cyber Aug 15, 2025
9cb0ce4
added little TODOs
Dunsin-cyber Aug 15, 2025
216b976
little mod
Dunsin-cyber Aug 16, 2025
52b0322
feat: create pin
Dunsin-cyber Aug 17, 2025
5774ec2
fix: update donate method
Dunsin-cyber Aug 17, 2025
d927145
feat: donate service complete
Dunsin-cyber Aug 18, 2025
f369b8c
task complete - done with necessary endpoints
Dunsin-cyber Aug 18, 2025
b77dddd
feat: add pagination
Dunsin-cyber Aug 18, 2025
f7b4e33
add docker start file for render
Dunsin-cyber Aug 18, 2025
ec54fd1
update node version in dockerfile
Dunsin-cyber Aug 18, 2025
4c0ab90
fixed module aliases and update usage.md
Dunsin-cyber Aug 18, 2025
fe605d0
updated uasge.md
Dunsin-cyber Aug 18, 2025
fd04b8a
update moduleAliases
Dunsin-cyber Aug 18, 2025
6ec14c0
fix: remove database migration from dev script
Dunsin-cyber Aug 22, 2025
5d50fb4
fix: show generic error message if from ORM and only return needed data
Dunsin-cyber Aug 22, 2025
8eb2880
fix: add remaining fix suggested during demo call
Dunsin-cyber Aug 22, 2025
60cc8b3
fix: add modifications suggested during demo call
Dunsin-cyber Aug 22, 2025
e17766d
update node version
Dunsin-cyber Aug 22, 2025
d6e5bc1
fix: build error fix
Dunsin-cyber Aug 22, 2025
f4e8664
change moduleAliases
Dunsin-cyber Aug 22, 2025
a87801d
fix: error message more user friendly
Dunsin-cyber Aug 24, 2025
125499a
fix: implement fix suggested during second demo
Dunsin-cyber Aug 24, 2025
7a4fb33
add transaction schema
Dunsin-cyber Aug 25, 2025
d5671f1
fix: seperate transactions from donation files
Dunsin-cyber Aug 25, 2025
e1b3b31
feat: create deopsit transaction on accounr creation from sydtem account
Dunsin-cyber Aug 25, 2025
0d4d0c2
feat: add pagination to get tranactions
Dunsin-cyber Aug 25, 2025
c2dcceb
feat: add transactionEntry relaton to user model
Dunsin-cyber Aug 27, 2025
4323636
feat: get a transaction endpint
Dunsin-cyber Aug 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
NODE_ENV=""
DATABASE_URL=""
JWT_REFRESH_SECRET=""
JWT_SECRET=""
PORT=""
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
.env
dist
35 changes: 35 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Use Node.js as the base image
FROM node:20.14.0

# Set the working directory
WORKDIR /app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN yarn install

# Copy the rest of the application code
COPY . .

# Generate Prisma Client
RUN npm run db:init

# Build the TypeScript project
RUN npm run build

# Declare a build-time variable
ARG DATABASE_URL

# Set it as an environment variable
ENV DATABASE_URL=${DATABASE_URL}

# Run migrations
RUN npm run db:deploy:prod

# Expose the application port
EXPOSE 3000

# Start the application
CMD ["node", "dist/server.js"]
111 changes: 111 additions & 0 deletions USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@


# Paritie Skill Test – Wallet & Donation Service

This project implements a simple wallet and donation API with built-in transaction safety, pagination, and authentication.

---

## 🚀 Features

* **Default Wallet Balance**: Every user automatically gets a wallet with a starting balance of **100,000 units**.
* **Send Funds by Email**: Users can send funds to beneficiaries using their registered email address.
* **Automatic Transaction Rollback**: Built-in safety mechanism in the **create donation** endpoint ensures that if any part of the process fails, funds are **automatically reversed**.
* **Pagination Support**: All resource fetch endpoints (users, donations, wallets) include pagination for efficient data retrieval.
* **Authentication**: Secure login & signup flow. Every request to protected endpoints requires a valid JWT access token.

---

## 🛠️ Getting Started

Follow these steps to set up the project locally:

```bash
# 1. Clone the repository
git clone https://github.com/Dunsin-cyber/backend-test/tree/main

# 2. Install dependencies
yarn install

# 3. Copy environment variables
cp .env.example .env
```

### ⚙️ Environment Setup

You need a PostgreSQL database connection string.
Create a database from any **Postgres provider** and copy the connection URL.
It should look like this:

```
postgresql://USER:PASSWORD@HOST:PORT/DATABASE
```

Set this value in your `.env` file as `DATABASE_URL`.
Also fill in other required values like:

* `NODE_ENV`
* `JWT_SECRET`
* `PORT` etc

---



## ▶️ Running the Project

Start the development server with:

```bash
yarn dev
```

Run the seed data
`yarn run db:seed` to create a paritie system account

If everything is working, you’ll see logs like this:

```bash
[nodemon] starting `ts-node -r tsconfig-paths/register src/server.ts`
Application started with config Loaded up✅
Server running on port [PORT]
API documentation available at 📝📚 http://localhost:[PORT]/api-docs
```

Now you can open the documentation link in your browser to test the APIs.

---

## 🌍 Deployed Service

A hosted version of this service is available at:

* **Backend URL** → [https://backend-test-21ij.onrender.com](https://backend-test-21ij.onrender.com)
* **API Docs** → http://localhost:[PORT]/api-docs

⚠️ **Note**:

* The hosting and database are on **free plans** and may be slow or unavailable.
* The database linked to this project will **expire on September 13, 2025**.

---

## 🔑 Authentication

Most endpoints are **protected**. To access them:

1. **Create an account** or **login** to get an `accessToken`.
2. The token is valid for **15 minutes**.
3. In the API docs (`/api-docs`), click the **Authorize** button (top right).
4. Paste the token into the input field and click **Authorize**.
5. You can now access protected routes directly from the Swagger UI.

---

## ✅ Summary

* Every user starts with **100,000 units** in their wallet.
* Transactions are **safe with auto-reversal** on failure.
* **Pagination** makes large data queries efficient.
* Fully documented and easy to test using Swagger.

7 changes: 7 additions & 0 deletions module-alias.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const moduleAlias = require("module-alias");
const path = require("path");

const isProd = process.env.NODE_ENV === "production";
const basePath = isProd ? "dist" : "src";

moduleAlias.addAlias("@", path.join(__dirname, basePath));
71 changes: 71 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"name": "backend-test",
"version": "1.0.0",
"description": "backend-coding-exercise",
"main": "src/server.ts",
"repository": "https://github.com/Dunsin-cyber/backend-test.git",
"author": "Dunsin <ayodejiabisuwa23@gmail.com>",
"license": "MIT",
"private": false,
"scripts": {
"clean": "rimraf dist",
"prestart": "node dist/constants/index.js",
"dev": "nodemon --legacy-watch -r tsconfig-paths/register src/server.ts",
"build": "npm run clean && tsc && cp -r src/prisma/ dist/prisma/",
"db:deploy": "cd ./src && npx prisma migrate deploy",
"db:reset": "cd ./src && npx prisma migrate reset --force",
"db:migrate": "cd ./src && npx prisma migrate dev --name rename_field_to_transactionEntries",
"db:init": "cd ./src && npx prisma generate",
"start": "node dist/server.js",
"start:prod": "npm run db:deploy:prod && npm run start",
"db:deploy:prod": "cd ./dist && npx prisma migrate deploy",
"db:seed": "npx prisma db seed --schema ./src/prisma/schema.prisma"
},
"prisma": {
"seed": "ts-node ./src/prisma/seed.ts"
},
"_moduleAliases": {
"@": "./src"
},
"dependencies": {
"@prisma/client": "^6.14.0",
"@prisma/extension-accelerate": "^2.0.2",
"bcryptjs": "^3.0.2",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"crypto": "^1.0.1",
"dotenv": "^16.4.7",
"express": "^4.21.2",
"express-session": "^1.18.1",
"jsonwebtoken": "^9.0.2",
"module-alias": "^2.2.3",
"morgan": "^1.10.0",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"tsconfig-paths": "^4.2.0",
"ulid": "^3.0.0",
"uuid": "^11.1.0"
},
"devDependencies": {
"@types/cookie-parser": "^1.4.8",
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/express-session": "^1.18.1",
"@types/jsonwebtoken": "^9.0.9",
"@types/module-alias": "^2.0.4",
"@types/morgan": "^1.9.9",
"@types/node": "^22.13.10",
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.8",
"@types/yamljs": "^0.2.34",
"nodemon": "^3.1.10",
"prisma": "^6.14.0",
"rimraf": "^6.0.1",
"ts-node": "^10.9.2",
"typescript": "^5.8.2"
},
"engines": {
"node": "^22.14.0",
"yarn": "^1.22.19"
}
}
5 changes: 5 additions & 0 deletions src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
# Keep environment variables out of version control
.env

/src/generated/prisma
39 changes: 39 additions & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import dotenv from 'dotenv';
// import { CipherKey } from 'crypto';
dotenv.config();


// MAKES SURE THAT ALL VARIABLES ARE IN ENV BEFPRE APP STARTS
// ? DATABASE_URL won't be exported because the new format has a "postgres" prifix which
// ? doesnt parse wellif imported through this format
const requiredEnvVars = [
'NODE_ENV',
'JWT_REFRESH_SECRET',
'JWT_SECRET'
];

const missingEnvVars = requiredEnvVars.filter(envVar => !process.env[envVar]);

if (missingEnvVars.length > 0) {
console.error(`❌ Missing required environment variables: ${missingEnvVars.join(', ')}`);
process.exit(1);
}



// ? SYSTEM CREDENTIALS
const NODE_ENV = process.env.NODE_ENV
const PORT = process.env.PORT || 3000;

// ? JWT CREDENTIALS
const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET;
const JWT_SECRET = process.env.JWT_SECRET;


export const config = {
NODE_ENV,
PORT,
JWT_REFRESH_SECRET,
JWT_SECRET

}
Loading