AI Review Center
Commit Review Workspace ?
Select a commit on the left to inspect quality, security, business value, findings, and suggested code changes.
Project AI Score
?
67%
Quality Avg
?
69%
Security Avg
?
64%
Reviews
?
143
Review Result ?
solutionbowl/tenant-service · f269636f
The commit adds a runner withdrawal API that voids bets and recalculates exposures accordingly, which has practical business value for managing race bets dynamically. The code integrates deeply with betting models and recalculates exposures carefully. However, the implementation lacks some code comments in critical parts, and error handling seems insufficient or commented out. The security risk is moderate because financial transactions like wallet refunds and ledger entries are handled, but the code review shows no explicit input validation or authorization checks to prevent misuse or injection attacks. Bug risk exists due to complexity and limited error logging or rollback mechanisms on partial failures. The fake work risk is low considering the complexity and meaningful domain logic shown.
Quality
?
75%
Security
?
50%
Business Value
?
70%
Maintainability
?
68%
Issues & Suggested Fixes
?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Error Logging Is Commented Out
Where
src/controllers/horseracing/test.controller.js:55
Issue / Evidence
error logging is commented out
Suggested Fix
uncomment or improve error logging to help debugging
Placeholder Console.log Statements Comment...
Where
src/controllers/horseracing/test.controller.js:158
Issue / Evidence
placeholder console.log statements commented out
Suggested Fix
remove or replace with proper logging or debugging
Success Message Sent, But No Error Handlin...
Where
src/controllers/horseracing/test.controller.js:236
Issue / Evidence
success message sent, but no error handling in access workflow
Suggested Fix
add try-catch blocks and error response handling
Fetching Market Data With Find Without Ver...
Where
src/controllers/horseracing/test.controller.js:120
Issue / Evidence
fetching market data with find without verifying existence
Suggested Fix
add checks and handle missing market data gracefully
Missing Validation
Where
src/controllers/horseracing/test.controller.js:137
Issue / Evidence
wallet refund logic present but no validation of wallet balance or transaction safety
Suggested Fix
add validations and atomic transactions if possible
Ledger Credit Entry Lacks Concurrency Cont...
Where
src/controllers/horseracing/test.controller.js:143
Issue / Evidence
ledger credit entry lacks concurrency control
Suggested Fix
consider transaction or locking mechanisms
Missing Validation
Where
src/controllers/horseracing/test.controller.js:190
Issue / Evidence
object ids created but without validation or sanitization
Suggested Fix
validate all external input before usage
Aggregation Pipelines Depend Heavily On Ob...
Where
src/utils/exposureHelper.js:49
Issue / Evidence
aggregation pipelines depend heavily on object ids and string conversions
Suggested Fix
ensure inputs are validated before queries to avoid injections
Security Issue
Where
src/routes/test.routes.js:7
Issue / Evidence
no authentication or authorization middlewares shown
Suggested Fix
add middleware to secure API endpoint
Insufficient Description
Where
commit message
Issue / Evidence
insufficient description
Suggested Fix
expand commit message to describe key business logic and security considerations of runner withdrawal
Code Change Preview · src/controllers/horseracing/test.controller.js
?
Removed / Before Commit
- diff --git a/src/controllers/horseracing/test.controller.js b/src/controllers/horseracing/test.controller.js - index 5381652..f05c28c 100644 - const mongoose = require("mongoose"); - const Exposure = require("../../models/Exposure"); - - exports.getTenantExposure = async (req, res) => { - try { - - return res.status(200).json({ success: true, data }); - } catch (error) { - console.error("Error fetching tenant exposure:", error); - return res.status(500).json({ success: false, message: "Server error fetching tenant exposure" }); - } - }; - exports.runnerWithdrawal = async (req, res) => { - try { - const { runner_id, race_id } = req.body; - const tenant = req.tenant;
Added / After Commit
+ diff --git a/src/controllers/horseracing/test.controller.js b/src/controllers/horseracing/test.controller.js + index 5381652..f05c28c 100644 + const mongoose = require("mongoose"); + const Exposure = require("../../models/Exposure"); + const Bet = require("../../models/Bet"); + const RacingBet = require("../../models/RacingBet"); + const Wallet = require("../../models/Wallet"); + const Ledger = require("../../models/Ledger"); + const { recalculatePlacesExposure } = require("../../utils/exposureHelper"); + const HorseRaceEvent = require("../../models/HorseRaceEvent"); + const HorseRace = require("../../models/HorseRace"); + const RaceMarket = require("../../models/RaceMarket"); + + exports.getTenantExposure = async (req, res) => { + try { + + return res.status(200).json({ success: true, data }); + } catch (error) {
Removed / Before Commit
- diff --git a/src/routes/test.routes.js b/src/routes/test.routes.js - index e0984ec..9d50abc 100644 - - // Test Route for Exposure - router.post("/exposure", testController.getTenantExposure); - - module.exports = router;
Added / After Commit
+ diff --git a/src/routes/test.routes.js b/src/routes/test.routes.js + index e0984ec..9d50abc 100644 + + // Test Route for Exposure + router.post("/exposure", testController.getTenantExposure); + router.post("/runnerWithdrawal", testController.runnerWithdrawal); + + module.exports = router;
Removed / Before Commit
- diff --git a/src/utils/exposureHelper.js b/src/utils/exposureHelper.js - index 453d352..5ff3d62 100644 - const mongoose = require("mongoose"); - const Exposure = require("../models/Exposure"); - - const getTenantExposure = async ({ raceId, tenantId }) => { - return await Exposure.aggregate([ - market.odds.forEach(runner => { - const exp = exposureData.find( - e => String(e._id.market_id) === String(market.marketId) && - String(e._id.runner_id) === String(runner.runnerId) - ); - - runner.exposure = exp ? exp.exposure : 0; - - return cloned; - }; - // const mergeExposure = (marketData, exposureData) => {
Added / After Commit
+ diff --git a/src/utils/exposureHelper.js b/src/utils/exposureHelper.js + index 453d352..5ff3d62 100644 + const mongoose = require("mongoose"); + const Exposure = require("../models/Exposure"); + const Bet = require("../models/Bet"); + const RacingBet = require("../models/RacingBet"); + + const getTenantExposure = async ({ raceId, tenantId }) => { + return await Exposure.aggregate([ + market.odds.forEach(runner => { + const exp = exposureData.find( + e => String(e._id.market_id) === String(market.marketId) && + String(e._id.runner_id) === String(runner.runnerId) + ); + + runner.exposure = exp ? exp.exposure : 0; + + return cloned;
Removed / Before Commit
- diff --git a/src/utils/socketClient.js b/src/utils/socketClient.js - index 2bcfeed..157d463 100644 - const { io } = require("socket.io-client"); - - let socket = null; - - return socket; - }; - - const emitRaceOdds = (raceId, oddsData) => { - const s = getSocket(); - s.emit("raceOdds", { raceId, oddsData }); - }; - - module.exports = { getSocket, emitRaceOdds };
Added / After Commit
+ diff --git a/src/utils/socketClient.js b/src/utils/socketClient.js + index 2bcfeed..157d463 100644 + const { io } = require("socket.io-client"); + const Exposure = require("../models/Exposure"); + const mongoose = require("mongoose"); + + + let socket = null; + + return socket; + }; + + const emitRaceOdds = async (raceId, oddsData, tenantId = null) => { + const s = getSocket(); + + // 1️⃣ Emit raw odds to everyone (no exposure mixed in) + s.emit(`raceOdds`, { raceId, oddsData }); +