From 484a0dd51a12d8682278fe8097879a310bb4f171 Mon Sep 17 00:00:00 2001 From: asif Date: Wed, 27 Aug 2025 12:29:27 +0530 Subject: [PATCH 1/9] added beneficiary deletion feature --- src/controllers/beneficiary.controller.js | 19 +++++++++++++++++++ src/routes/beneficiary.route.js | 4 ++++ src/services/beneficiary.service.js | 11 +++++++++++ 3 files changed, 34 insertions(+) diff --git a/src/controllers/beneficiary.controller.js b/src/controllers/beneficiary.controller.js index ccac3bf..b59d2db 100644 --- a/src/controllers/beneficiary.controller.js +++ b/src/controllers/beneficiary.controller.js @@ -95,6 +95,24 @@ async function getBeneficiary(req, res) { } } +async function deleteBeneficiary(req, res) { + const { beneficiaryAccountNo } = req.params; + try { + await beneficiaryService.deleteBeneficiary(req.user, beneficiaryAccountNo); + res.status(204).send(); + } catch (error) { + if (error.message === 'ACCOUNT_NOT_FOUND') { + logger.warn( + `beneficiary ${beneficiaryAccountNo} does not exist for the customer ${req.user}` + ); + return res.status(400).json({ error: 'INVALID_BENEFICIARY_ACCOUNT_NO' }); + } else { + logger.error(error, 'error deleting beneficiary'); + return res.status(500).json({ error: 'INTERNAL_SERVER_ERROR' }); + } + } +} + async function getIfscDetails(req, res) { const { ifscCode } = req.query; if (!ifscCode) { @@ -127,4 +145,5 @@ module.exports = { addBeneficiary, getIfscDetails, getBeneficiary, + deleteBeneficiary, }; diff --git a/src/routes/beneficiary.route.js b/src/routes/beneficiary.route.js index d1483d8..47e7eba 100644 --- a/src/routes/beneficiary.route.js +++ b/src/routes/beneficiary.route.js @@ -9,5 +9,9 @@ router.get('/validate/outside-bank', beneficiaryController.validateOutsideBank); router.get('/ifsc-details', beneficiaryController.getIfscDetails); router.get('/', beneficiaryController.getBeneficiary); router.post('/', newBeneficiaryValidator, beneficiaryController.addBeneficiary); +router.delete( + '/:beneficiaryAccountNo', + beneficiaryController.deleteBeneficiary +); module.exports = router; diff --git a/src/services/beneficiary.service.js b/src/services/beneficiary.service.js index 136f3d1..1eeb7d1 100644 --- a/src/services/beneficiary.service.js +++ b/src/services/beneficiary.service.js @@ -44,6 +44,16 @@ async function getSingleBeneficiary(customerNo, accountNo) { return result.rows[0]; } +async function deleteBeneficiary(customerNo, beneficiaryAccountNo) { + const queryStr = + 'DELETE FROM beneficiaries WHERE customer_no = $1 AND account_no = $2'; + const result = await db.query(queryStr, [customerNo, beneficiaryAccountNo]); + if (result.rowCount == 0) { + throw new Error('ACCOUNT_NOT_FOUND'); + } + return; +} + async function getAllBeneficiaries(customerNo) { const queryStr = 'SELECT b.account_no, b.name, b.account_type, b.ifsc_code, i.bank_name, i.branch_name FROM beneficiaries b JOIN ifsc_details i ON b.ifsc_code = i.ifsc_code WHERE customer_no = $1'; @@ -66,4 +76,5 @@ module.exports = { validateOutsideBank, getAllBeneficiaries, getSingleBeneficiary, + deleteBeneficiary, }; From c8efe8d75a6af8bb5c058d37f8899c5a0b4b9e1f Mon Sep 17 00:00:00 2001 From: asif Date: Fri, 29 Aug 2025 13:40:57 +0530 Subject: [PATCH 2/9] fix: check if password is not null on login req --- src/controllers/auth.controller.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/controllers/auth.controller.js b/src/controllers/auth.controller.js index 9a90add..94e23f8 100644 --- a/src/controllers/auth.controller.js +++ b/src/controllers/auth.controller.js @@ -14,7 +14,8 @@ async function login(req, res) { const currentTime = new Date().toISOString(); try { const user = await authService.validateUser(customerNo, password); - if (!user) return res.status(401).json({ error: 'invalid credentials' }); + if (!user || !password) + return res.status(401).json({ error: 'invalid credentials' }); const token = generateToken(user.customer_no, '1d'); const FirstTimeLogin = await authService.CheckFirstTimeLogin(customerNo); await db.query('UPDATE users SET last_login = $1 WHERE customer_no = $2', [ @@ -34,7 +35,6 @@ async function fetchUserDetails(req, res) { const user = await authService.findUserByCustomerNo(customerNo); if (!user) return res.status(404).json({ message: 'USER_NOT_FOUND' }); return res.json(user); - } catch (err) { logger.error(err, 'error occured while fetching user details'); res.status(500).json({ error: 'something went wrong' }); @@ -102,4 +102,11 @@ async function setTransactionPassword(req, res) { } } -module.exports = { login, tpin, setTpin, setLoginPassword, setTransactionPassword,fetchUserDetails }; +module.exports = { + login, + tpin, + setTpin, + setLoginPassword, + setTransactionPassword, + fetchUserDetails, +}; From 077d48c7f0d5d7c888fef4d74b655eec5b027e63 Mon Sep 17 00:00:00 2001 From: asif Date: Fri, 29 Aug 2025 15:40:11 +0530 Subject: [PATCH 3/9] added logger for logging all kinds of requests with headers, body, ip and other data --- src/app.js | 22 +++++++++++++++++++++- src/util/logger.js | 25 +++++++++++++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/app.js b/src/app.js index 3c86b46..42b45f6 100644 --- a/src/app.js +++ b/src/app.js @@ -1,6 +1,6 @@ const express = require('express'); const cors = require('cors'); -const { logger } = require('./util/logger'); +const { logger, requestLogger } = require('./util/logger'); const routes = require('./routes'); const app = express(); @@ -9,6 +9,26 @@ app.use(cors()); app.use(express.json()); app.use(express.urlencoded({ extended: true })); +app.use((req, res, next) => { + const start = Date.now(); + + res.on('finish', () => { + requestLogger.info( + { + ip: req.ip || req.connection.remoteAddress, + method: req.method, + url: req.originalUrl, + headers: req.headers, + body: req.body, + status: res.statusCode, + responseTime: `${Date.now() - start}ms`, + }, + 'Incoming request' + ); + }); + next(); +}); + app.use('/api', routes); app.get('/health', (_, res) => res.send('server is healthy')); app.use((err, _req, res, _next) => { diff --git a/src/util/logger.js b/src/util/logger.js index eb033b0..4b6d33a 100644 --- a/src/util/logger.js +++ b/src/util/logger.js @@ -1,6 +1,19 @@ const pino = require('pino'); +const fs = require('fs'); +const path = require('path'); + const isDev = process.env.NODE_ENV !== 'production'; +const logDir = path.join(__dirname, 'logs'); +if (!fs.existsSync(logDir)) { + fs.mkdirSync(logDir); +} + +const requestLoggerStream = pino.destination({ + dest: path.join(logDir, 'requests.log'), + sync: false, +}); + const logger = pino({ transport: isDev ? { @@ -15,8 +28,12 @@ const logger = pino({ level: isDev ? 'debug' : 'info', }); -const requestLogger = (req, _res, next) => { - logger.info(`${req.method} ${req.url}`); - next(); -}; +const requestLogger = pino( + { + level: 'info', + base: null, + }, + requestLoggerStream +); + module.exports = { logger, requestLogger }; From 454553adbb53fb897364e93825d7defca978ba2e Mon Sep 17 00:00:00 2001 From: asif Date: Fri, 29 Aug 2025 15:40:36 +0530 Subject: [PATCH 4/9] added log files in .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 713d500..81b138d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ .env +src/util/logs/requests.log From 50753295b464f626fb825a3fd615979f56cee54b Mon Sep 17 00:00:00 2001 From: asif Date: Fri, 29 Aug 2025 15:49:35 +0530 Subject: [PATCH 5/9] changed the directory of log directory --- .gitignore | 2 +- src/util/logger.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 81b138d..dbef8e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ node_modules/ .env -src/util/logs/requests.log +logs/requests.log diff --git a/src/util/logger.js b/src/util/logger.js index 4b6d33a..18c891f 100644 --- a/src/util/logger.js +++ b/src/util/logger.js @@ -4,7 +4,7 @@ const path = require('path'); const isDev = process.env.NODE_ENV !== 'production'; -const logDir = path.join(__dirname, 'logs'); +const logDir = path.join(__dirname, '../..', 'logs'); if (!fs.existsSync(logDir)) { fs.mkdirSync(logDir); } From 05068634fe4bb0596502b2ace62c1ca5c19a1819 Mon Sep 17 00:00:00 2001 From: asif Date: Mon, 8 Sep 2025 16:33:03 +0530 Subject: [PATCH 6/9] added empty string as default narration value in transfer --- src/controllers/transfer.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/transfer.controller.js b/src/controllers/transfer.controller.js index 2f9bc6c..d0688e3 100644 --- a/src/controllers/transfer.controller.js +++ b/src/controllers/transfer.controller.js @@ -6,7 +6,7 @@ async function transfer( toAccountType, amount, // narration = 'transfer from mobile' - narration + narration = '' ) { try { const response = await axios.post( From f675f1561a6ef8c231858972b5a45d1ca565a005 Mon Sep 17 00:00:00 2001 From: asif Date: Mon, 8 Sep 2025 20:04:55 +0530 Subject: [PATCH 7/9] feat: added transactions record keeping feature --- src/controllers/imps.controller.js | 17 ++++++++- src/controllers/neft.controller.js | 19 +++++++++- src/controllers/rtgs.controller.js | 19 +++++++++- src/controllers/transfer.controller.js | 13 ++++++- src/routes/imps.route.js | 1 + src/routes/neft.route.js | 1 + src/routes/rtgs.route.js | 1 + src/routes/transfer.route.js | 3 +- src/services/recordkeeping.service.js | 52 ++++++++++++++++++++++++++ 9 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 src/services/recordkeeping.service.js diff --git a/src/controllers/imps.controller.js b/src/controllers/imps.controller.js index 0eb933d..7833ad2 100644 --- a/src/controllers/imps.controller.js +++ b/src/controllers/imps.controller.js @@ -1,7 +1,11 @@ const axios = require('axios'); const { logger } = require('../util/logger'); +const { + recordInterBankTransaction, +} = require('../services/recordkeeping.service'); async function send( + customerNo, fromAccount, toAccount, amount, @@ -20,7 +24,6 @@ async function send( stTransferAmount: amount, stRemarks: remarks, }; - logger.info(reqData, 'request data to be sent to IMPS server'); const response = await axios.post( 'http://localhost:6768/kccb/api/IMPS/Producer', reqData, @@ -30,7 +33,17 @@ async function send( }, } ); - logger.info(response, 'response from IMPS'); + await recordInterBankTransaction( + customerNo, + 'imps', + fromAccount, + toAccount, + ifscCode, + amount, + '', + '', + response.data + ); return response.data; } catch (error) { logger.error(error, 'error from IMPS'); diff --git a/src/controllers/neft.controller.js b/src/controllers/neft.controller.js index 091b7a3..a43acd8 100644 --- a/src/controllers/neft.controller.js +++ b/src/controllers/neft.controller.js @@ -1,6 +1,10 @@ const axios = require('axios'); +const { + recordInterBankTransaction, +} = require('../services/recordkeeping.service'); async function send( + customerNo, fromAccount, toAccount, amount, @@ -8,6 +12,7 @@ async function send( beneficiaryName, remitterName ) { + const commission = 0; try { const response = await axios.post( 'http://localhost:8690/kccb/Neftfundtransfer', @@ -15,7 +20,7 @@ async function send( stFromAcc: fromAccount, stToAcc: toAccount, stTranAmt: amount, - stCommission: 0, + stCommission: commission, stIfscCode: ifscCode, stFullName: remitterName, stBeneName: beneficiaryName, @@ -24,6 +29,18 @@ async function send( stAddress3: '', } ); + await recordInterBankTransaction( + customerNo, + 'neft', + fromAccount, + toAccount, + ifscCode, + amount, + commission, + beneficiaryName, + remitterName, + response.data.status + ); return response.data; } catch (error) { throw new Error( diff --git a/src/controllers/rtgs.controller.js b/src/controllers/rtgs.controller.js index e5c9625..352cf21 100644 --- a/src/controllers/rtgs.controller.js +++ b/src/controllers/rtgs.controller.js @@ -1,6 +1,10 @@ const axios = require('axios'); +const { + recordInterBankTransaction, +} = require('../services/recordkeeping.service'); async function send( + customerNo, fromAccount, toAccount, amount, @@ -8,6 +12,7 @@ async function send( beneficiaryName, remitterName ) { + const commission = 0; try { const response = await axios.post( 'http://localhost:8690/kccb/Rtgsfundtransfer', @@ -15,7 +20,7 @@ async function send( stFromAcc: fromAccount, stToAcc: toAccount, stTranAmt: amount, - stCommission: 0, + stCommission: commission, stIfscCode: ifscCode, stFullName: remitterName, stBeneName: beneficiaryName, @@ -24,6 +29,18 @@ async function send( stAddress3: '', } ); + await recordInterBankTransaction( + customerNo, + 'rtgs', + fromAccount, + toAccount, + ifscCode, + amount, + commission, + beneficiaryName, + remitterName, + response.data.status + ); return response.data; } catch (error) { throw new Error( diff --git a/src/controllers/transfer.controller.js b/src/controllers/transfer.controller.js index d0688e3..028c49d 100644 --- a/src/controllers/transfer.controller.js +++ b/src/controllers/transfer.controller.js @@ -1,11 +1,14 @@ const axios = require('axios'); +const { + recordIntraBankTransaction, +} = require('../services/recordkeeping.service'); async function transfer( fromAccountNo, toAccountNo, toAccountType, amount, - // narration = 'transfer from mobile' + customerNo, narration = '' ) { try { @@ -19,6 +22,14 @@ async function transfer( narration, } ); + await recordIntraBankTransaction( + customerNo, + fromAccountNo, + toAccountNo, + toAccountType, + amount, + response.data.status + ); return response.data; } catch (error) { throw new Error( diff --git a/src/routes/imps.route.js b/src/routes/imps.route.js index d0ff998..5294270 100644 --- a/src/routes/imps.route.js +++ b/src/routes/imps.route.js @@ -13,6 +13,7 @@ const impsRoute = async (req, res) => { try { const result = await impsController.send( + req.user, fromAccount, toAccount, amount, diff --git a/src/routes/neft.route.js b/src/routes/neft.route.js index 89342b3..ae5d78b 100644 --- a/src/routes/neft.route.js +++ b/src/routes/neft.route.js @@ -19,6 +19,7 @@ const neftRoute = async (req, res) => { try { const result = await neftController.send( + req.user, fromAccount, toAccount, amount, diff --git a/src/routes/rtgs.route.js b/src/routes/rtgs.route.js index c0832c5..14ed607 100644 --- a/src/routes/rtgs.route.js +++ b/src/routes/rtgs.route.js @@ -19,6 +19,7 @@ const rtgsRoute = async (req, res) => { try { const result = await rtgsController.send( + req.user, fromAccount, toAccount, amount, diff --git a/src/routes/transfer.route.js b/src/routes/transfer.route.js index 3fd9afa..349dd3e 100644 --- a/src/routes/transfer.route.js +++ b/src/routes/transfer.route.js @@ -14,7 +14,8 @@ const transferRoute = async (req, res) => { fromAccount, toAccount, toAccountType, - amount + amount, + req.user ); if (result.status === 'O.K.') { diff --git a/src/services/recordkeeping.service.js b/src/services/recordkeeping.service.js new file mode 100644 index 0000000..43fa20a --- /dev/null +++ b/src/services/recordkeeping.service.js @@ -0,0 +1,52 @@ +const db = require('../config/db'); + +const recordIntraBankTransaction = async ( + customerNo, + fromAccount, + toAccount, + accountType, + amount, + status +) => { + const trxType = 'TRF'; + const query = + 'INSERT INTO transactions (customer_no, trx_type, from_account, to_account, to_account_type, amount, status) VALUES ($1, $2, $3, $4, $5, $6, $7)'; + await db.query(query, [ + customerNo, + trxType, + fromAccount, + toAccount, + accountType, + amount, + status, + ]); +}; +const recordInterBankTransaction = async ( + customerNo, + trxType, + fromAccount, + toAccount, + ifscCode, + amount, + commission, + beneficiaryName, + remitterName, + status +) => { + const query = + 'INSERT INTO transactions (customer_no, trx_type, from_account, to_account, ifsc_code, amount, commission, beneficiary_name, remitter_name, status) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)'; + await db.query(query, [ + customerNo, + trxType, + fromAccount, + toAccount, + ifscCode, + amount, + commission, + beneficiaryName, + remitterName, + status, + ]); +}; + +module.exports = { recordIntraBankTransaction, recordInterBankTransaction }; From 3da77cf97ab9bd7ec28dbf7bc67e6f6ef34e8c6a Mon Sep 17 00:00:00 2001 From: asif Date: Mon, 8 Sep 2025 20:32:19 +0530 Subject: [PATCH 8/9] feat: added account balance in statement --- src/controllers/transactions.controller.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/controllers/transactions.controller.js b/src/controllers/transactions.controller.js index 297ae8c..169cd1c 100644 --- a/src/controllers/transactions.controller.js +++ b/src/controllers/transactions.controller.js @@ -13,6 +13,8 @@ async function getLastTen(accountNumber) { date: tx.stTransactionDate, amount: tx.stTransactionAmount.slice(0, -3), type: tx.stTransactionAmount.slice(-2), + balance: tx.stAccountBalance.slice(0, -3), + balanceType: tx.stAccountBalance.slice(-2), })); return processedTransactions; } catch (error) { @@ -36,6 +38,8 @@ async function getFiltered(accountNumber, fromDate, toDate) { date: tx.stTransactionDate, amount: tx.stTransactionAmount.slice(0, -3), type: tx.stTransactionAmount.slice(-2), + balance: tx.stAccountBalance.slice(0, -3), + balanceType: tx.stAccountBalance.slice(-2), })); return processedTransactions; } catch (error) { From 2516ff5f4c8f97d4ba8e7679e27950e6f4a77e05 Mon Sep 17 00:00:00 2001 From: asif Date: Tue, 9 Sep 2025 02:11:43 +0530 Subject: [PATCH 9/9] added helmet for security --- src/app.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app.js b/src/app.js index 42b45f6..254e856 100644 --- a/src/app.js +++ b/src/app.js @@ -2,10 +2,12 @@ const express = require('express'); const cors = require('cors'); const { logger, requestLogger } = require('./util/logger'); const routes = require('./routes'); +const helmet = require('helmet'); const app = express(); app.use(cors()); +app.use(helmet()); app.use(express.json()); app.use(express.urlencoded({ extended: true }));