Backend schema change - #121
Conversation
tarinagarwal
left a comment
There was a problem hiding this comment.
Great work on the Labs CRUD implementation! The core functionality is solid. A few improvements needed:
1. Use existing Prisma instance
Replace const prisma = new PrismaClient(); with import prisma from "../db.js"; to use the existing connection.
2. Add input validation
- Validate required fields (title, language, difficulty, etc.)
- Validate enum values for difficulty ("beginner", "intermediate", "advanced")
- Validate visibility ("private", "public", "link")
3. Add filters to GET /api/labs
Add query parameter support for filtering by language, difficulty, creator, etc.
4. Minor fixes
- Add newline at end of schema.prisma file
- Add basic validation for empty/invalid ObjectIds
5. Error handling
Add validation for invalid ObjectId format in route parameters.
The MongoDB adaptations and ObjectId usage are perfect for this setup. Core CRUD logic and auth checks look excellent!
|
Hello, @tarinagarwal |
|
Hello @tarinagarwal please review the changes |
|
@Priyamanjare54 going thru it |
|
Hello any changes required? |
There was a problem hiding this comment.
Changes Requested 🐈
This PR implements full CRUD functionality for Labs with JWT authentication and authorization. Review found critical performance issue due to missing pagination on GET /api/labs, multiple high-severity documentation gaps, and security concerns on unauthenticated GET endpoints. Additional improvements in validation, error handling, and code structure are recommended.
There are a few things I'd like to see addressed before we merge this:
Before merging
- Add pagination and limit to GET /api/labs endpoint to prevent performance degradation.
- Provide comprehensive API documentation for all Labs routes including methods, parameters, responses, authentication, and error handling.
- Implement authentication and authorization checks on GET endpoints and sanitize user inputs to mitigate security risks.
Findings breakdown (33 total)
1 critical / 6 high / 8 medium / 11 low / 7 info
Confidence: 95%
🔗 View Full Review Report — detailed findings, severity breakdown, and agent analysis
Reviewed by Looks Good To Meow — AI-powered code review
💬 You can interact with me directly in this PR:
@tarin-lgtm fix [any constraints]@tarin-lgtm explain [your question]@tarin-lgtm improve [focus area]@tarin-lgtm test [what to focus on]
| }); | ||
|
|
||
| // --- GET ALL Labs --- | ||
| router.get("/", async (req, res) => { |
There was a problem hiding this comment.
🚨 Critical — The GET /api/labs endpoint fetches all labs without any pagination or limit, potentially returning a very large dataset which can degrade performance and increase memory usage.
Implement pagination by accepting page and limit query parameters and use Prisma's skip and take options to limit the number of labs returned per request.
performance
| @@ -0,0 +1,199 @@ | |||
| import express from "express"; | |||
There was a problem hiding this comment.
Add comprehensive JSDoc or API documentation comments above each route handler describing the endpoint's purpose, HTTP method, URL path, expected request parameters and body schema, response format, authentication requirements, and possible error responses.
documentation
| const ALLOWED_VISIBILITY = ["private", "public", "link"]; | ||
|
|
||
| // --- CREATE Lab --- | ||
| router.post("/", authenticateToken, async (req, res) => { |
There was a problem hiding this comment.
Add JSDoc or API documentation for this endpoint specifying it is a POST request to create a lab, detailing required and optional fields in the request body, authentication via JWT, the structure of the success response, and possible error responses with status codes.
documentation
| }); | ||
|
|
||
| // --- GET ALL Labs --- | ||
| router.get("/", async (req, res) => { |
There was a problem hiding this comment.
Add documentation describing this GET endpoint, including optional query parameters (language, difficulty, creator), the structure of the returned labs array, and error responses.
documentation
| }); | ||
|
|
||
| // --- GET SINGLE Lab --- | ||
| router.get("/:id", async (req, res) => { |
There was a problem hiding this comment.
Add documentation specifying this GET endpoint accepts a lab ID as a path parameter, returns the lab object with related data, and possible error responses for invalid ID or not found.
documentation
| return res.status(400).json({ error: "Invalid visibility value" }); | ||
| } | ||
|
|
||
| const lab = await prisma.lab.update({ |
There was a problem hiding this comment.
💡 Suggestion — The PUT /:id route does not handle the case where no fields are provided for update, which may cause Prisma to update with undefined values.
Filter out undefined fields from the update data before passing to Prisma to avoid overwriting fields with undefined.
best-practices
|
|
||
| if (existing.creatorId !== req.user.id) return res.status(403).json({ error: "Forbidden" }); | ||
|
|
||
| await prisma.lab.delete({ where: { id } }); |
There was a problem hiding this comment.
💡 Suggestion — The DELETE /:id route returns a JSON message on success but does not set an explicit HTTP status code. The default 200 is acceptable but 204 No Content is more conventional for successful deletes.
Consider returning status 204 No Content with no body for successful DELETE requests to align with REST conventions.
best-practices
| }); | ||
|
|
||
| // --- UPDATE Lab --- | ||
| router.put("/:id", authenticateToken, async (req, res) => { |
There was a problem hiding this comment.
💡 Suggestion — The PUT /api/labs/:id endpoint updates lab fields without sanitizing or validating string inputs such as title, description, content, tasks, testCases, and solution. This could lead to stored XSS if these fields are rendered in a client without proper escaping.
Implement input sanitization or escaping for user-supplied string fields before storing them in the database. Additionally, consider validating the structure and content of complex fields like tasks and testCases.
security
| visibility, | ||
| } = req.body; | ||
|
|
||
| if (difficulty && !ALLOWED_DIFFICULTIES.includes(difficulty)) { |
There was a problem hiding this comment.
💡 Suggestion — In the UPDATE Lab route, the difficulty validation returns a generic error without listing allowed values, unlike the CREATE Lab route which provides allowed values for better client feedback.
Include the allowedValues array in the error response for consistency and better client-side validation feedback.
bugs
| return res.status(400).json({ error: "Invalid difficulty value" }); | ||
| } | ||
|
|
||
| if (visibility && !ALLOWED_VISIBILITY.includes(visibility)) { |
There was a problem hiding this comment.
💡 Suggestion — In the UPDATE Lab route, the visibility validation returns a generic error without listing allowed values, unlike the CREATE Lab route which provides allowed values for better client feedback.
Include the allowedValues array in the error response for consistency and better client-side validation feedback.
bugs
There was a problem hiding this comment.
Changes Requested 🐈
PR #121 adds Labs CRUD APIs with JWT auth and creator-only update/delete, plus a Prisma/Mongo replica set connection fix. Review flags several high-severity problems in server/routes/labs.js including a malformed/misaligned Prisma include block (potential runtime failure) and missing rate limiting, pagination, and endpoint documentation for state-changing and listing endpoints.
There are a few things I'd like to see addressed before we merge this:
Before merging
- Fix the malformed Prisma
includeblock / any likely syntax or brace/indentation issues inserver/routes/labs.js(validate route loads and queries are correct). - Add rate limiting (and ideally abuse controls) to authenticated state-changing endpoints: POST /labs, PUT /labs/:id, DELETE /labs/:id.
- Add pagination/limits for GET /api/labs and reduce eager relational includes; also fill in missing validation and endpoint documentation (request/response, auth rules, error cases).
Findings
🎯 6 actionable · 💡 4 suggestions
Severity breakdown (23 total)
6 high / 13 medium / 4 low
Confidence: 93%
🔗 View Full Review Report — detailed findings, severity breakdown, and agent analysis
Reviewed by Looks Good To Meow — AI-powered code review
| if (difficulty) where.difficulty = difficulty; | ||
| if (creator) where.creatorId = creator; | ||
|
|
||
| const labs = await prisma.lab.findMany({ |
There was a problem hiding this comment.
🎯 Actionable — High — The include block is malformed: progress: true is indented inconsistently and there’s a missing closing brace/parenthesis alignment, which can cause a runtime syntax error or incorrect query structure.
Fix the indentation/bracing so the include object is correctly closed before ending the findMany call.
Flagged by: best-practices, bugs, performance, readability
|
|
||
| if (existing.creatorId !== req.user.id) return res.status(403).json({ error: "Forbidden" }); | ||
|
|
||
| const { |
There was a problem hiding this comment.
🎯 Actionable — High — The update handler has inconsistent indentation around destructuring and const lab = await prisma.lab.update...; while not strictly semantic, this commonly indicates a missing brace/semicolon or mis-scoped block that can prevent the server from loading the route.
Reformat and verify all braces are balanced in the PUT /:id handler, ensuring the destructuring and update call are inside the try block.
Flagged by: best-practices, bugs, readability
| const ALLOWED_VISIBILITY = ["private", "public", "link"]; | ||
|
|
||
| // --- CREATE Lab --- | ||
| router.post("/", authenticateToken, async (req, res) => { |
There was a problem hiding this comment.
🎯 Actionable — High — The new lab creation endpoint accepts authenticated requests but has no rate limiting. An attacker with a valid token (or via token theft) could repeatedly create labs and cause storage/compute exhaustion in the database.
Flagged by: documentation, security
| }); | ||
|
|
||
| // --- DELETE Lab --- | ||
| router.delete("/:id", authenticateToken, async (req, res) => { |
There was a problem hiding this comment.
🎯 Actionable — High — The new DELETE lab endpoint is authenticated but has no rate limiting. With a valid token, an attacker could rapidly delete resources causing denial of service and integrity damage.
Flagged by: documentation, security
| }); | ||
|
|
||
| // --- UPDATE Lab --- | ||
| router.put("/:id", authenticateToken, async (req, res) => { |
There was a problem hiding this comment.
🎯 Actionable — High — The new lab update endpoint is authenticated but has no rate limiting. With a valid token, an attacker could repeatedly update labs to degrade service availability and increase database write load.
Flagged by: documentation, security
| }); | ||
|
|
||
| // --- GET ALL Labs --- | ||
| router.get("/", async (req, res) => { |
There was a problem hiding this comment.
🎯 Actionable — High — GET /api/labs returns an unbounded list of labs with no limit/offset (or cursor) controls. Under real usage, this can cause large payloads and slow database response times as the dataset grows.
Add pagination parameters (e.g., limit/offset or cursor) and apply them to prisma.lab.findMany; also consider selecting only needed fields and/or adding default sorting.
Flagged by: best-practices, documentation, performance
| return res.status(400).json({ | ||
| error: "Invalid visibility value", | ||
| allowedValues: ALLOWED_VISIBILITY, | ||
| }); |
There was a problem hiding this comment.
💡 Suggestion — Medium — visibility is validated only if truthy; this means an empty string bypasses validation but is still stored (or overwritten) with '', which may not match the intended enum values.
Validate visibility whenever the field is present in the request body (e.g., check visibility !== undefined), and reject empty strings.
Flagged by: bugs
| visibility, | ||
| } = req.body; | ||
|
|
||
| if (difficulty && !ALLOWED_DIFFICULTIES.includes(difficulty)) { |
There was a problem hiding this comment.
💡 Suggestion — Medium — In the update route, the enum validation also only runs when visibility/difficulty are truthy, so difficulty: '' or visibility: '' will bypass validation and be written to the database.
Change the conditionals to validate when the key is provided (e.g., difficulty !== undefined) rather than when it’s truthy.
Flagged by: bugs, readability
| const router = express.Router(); | ||
|
|
||
|
|
||
| const ALLOWED_DIFFICULTIES = ["beginner", "intermediate", "advanced"]; |
There was a problem hiding this comment.
💡 Suggestion — Medium — The route imports/exports are fine, but there are multiple indentation/formatting inconsistencies (e.g., uneven alignment around required fields and include blocks) that make reviews harder and increase the chance of introducing subtle syntax errors later.
Flagged by: best-practices
| }); | ||
|
|
||
| // --- GET SINGLE Lab --- | ||
| router.get("/:id", async (req, res) => { |
There was a problem hiding this comment.
💡 Suggestion — Medium — GET /api/labs/:id returns a lab with creator/shares/progress included, but there is no documentation for access control/visibility rules (especially for private/link labs) or response schema. This is non-obvious given the include fields and the presence of a custom ObjectId validator.
Document GET /api/labs/:id access rules (auth/visibility), required/optional response fields (including nested relations: creator, shares, progress), and explicit error responses (400 invalid ID, 404 not found, 500).
Flagged by: documentation
📝 Description
Implemented full Labs CRUD functionality with authentication and authorization.Fixes #58
Key highlights:
This completes the Labs module backend functionality and prepares it for frontend integration.
🔗 Related Issue
Closes: N/A
🏷️ Type of Change
📸 Screenshots (if applicable)
N/A (Backend-only changes)
✅ Checklist
🧪 Testing
How I tested:
Generated JWT token via login
Tested protected endpoints using Authorization header
Verified ownership checks for update/delete
Confirmed Prisma works with MongoDB replica set
Tested API endpoints (Postman)
Tested on Chrome
Tested on Firefox
Tested on mobile
📋 Additional Notes
201,403,404, etc.).SWOC 2026 Participant ✅
Please add the
swoc2026label to this PR 🎉