feat: add Projects management feature with CRUD API, frontend UI, and tests#480
feat: add Projects management feature with CRUD API, frontend UI, and tests#480devin-ai-integration[bot] wants to merge 1 commit intomainfrom
Conversation
… tests - Add projects table to database with name, description, client_id, start_date, status fields - Add Joi validation schemas for project creation and updates - Create RESTful API endpoints: GET/POST/PUT/DELETE /api/projects - Add 37 backend tests covering all CRUD operations and error handling - Add TypeScript types for Project, CreateProjectRequest, UpdateProjectRequest - Add API client methods for all project endpoints - Create ProjectsPage with table view, create/edit dialog, and delete functionality - Add Projects navigation item to sidebar with FolderOpen icon - Support project status (active/completed/on-hold) with color-coded chips - Support optional client assignment via dropdown
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
| db.run( | ||
| 'INSERT INTO projects (name, description, client_id, start_date, status, user_email) VALUES (?, ?, ?, ?, ?, ?)', | ||
| [name, description || null, clientId || null, startDate || null, status, req.userEmail], |
There was a problem hiding this comment.
🔴 Missing client ownership validation allows referencing other users' clients
The project create (POST /) and update (PUT /:id) routes accept a clientId and insert it directly into the database without verifying that the client belongs to the authenticated user. This allows a user to associate their project with another user's client by providing that client's ID via direct API calls.
The existing workEntries.js route validates this correctly — on create (workEntries.js:90-102) it checks SELECT id FROM clients WHERE id = ? AND user_email = ?, and on update (workEntries.js:174-193) it does the same when clientId is being changed. The projects route skips this validation entirely for both operations.
Prompt for agents
In backend/src/routes/projects.js, the POST / handler (create project) at line 75 and the PUT /:id handler (update project) around lines 154-157 both accept a clientId and pass it directly to the database without verifying that the client belongs to the authenticated user (req.userEmail).
The established pattern for this validation can be seen in backend/src/routes/workEntries.js. In the POST handler (lines 90-102), before inserting the work entry, it runs:
db.get('SELECT id FROM clients WHERE id = ? AND user_email = ?', [clientId, req.userEmail], ...)
and returns a 400 error if the client is not found.
Similarly, in the PUT handler (lines 174-193), it conditionally validates the clientId if it's being updated.
Apply the same pattern to both the POST and PUT handlers in projects.js:
1. In POST /, before the INSERT, check that clientId (when provided and non-null) belongs to the user
2. In PUT /:id, when value.clientId is provided and non-null, verify it belongs to the user before including it in the update query
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Adds a full "Projects" management feature to the timesheet app, following existing codebase patterns (clients, work entries).
Backend:
projectstable in SQLite with fields:name,description,client_id(FK to clients),start_date,status(active/completed/on-hold),user_emailprojectSchema,updateProjectSchema) with status enum constraint/api/projects(GET list, GET by id, POST, PUT, DELETE by id, DELETE all)client_namein responsesFrontend:
Project/CreateProjectRequest/UpdateProjectRequestTypeScript typesProjectsPagecomponent with table view, create/edit dialog (with client dropdown + status selector + date picker), delete with confirmationReview & Testing Checklist for Human
startDatestorage format: Joi'sJoi.date().iso()converts input strings into JavaScriptDateobjects. When these are passed to the SQLite driver, they may be stored asDate.toString()(e.g."Wed Jan 01 2024 00:00:00 GMT+0000") rather than the expected ISO format. Manually create a project with a start date and verify what gets stored/returned. (This same pattern exists inworkEntrySchema— may be a pre-existing issue.)clientIdreferences an existing client before inserting. SQLite FK constraints are not enforced (noPRAGMA foreign_keys = ONininit.js). Try creating a project withclientId: 99999and confirm the behavior is acceptable.ON DELETE SET NULLbehavior: Delete a client that is assigned to a project and verify the project'sclient_idbecomes null (note: this depends on FK enforcement being enabled, which it currently is not).Notes
DELETE /api/projectsendpoint follows the same pattern asDELETE /api/clients— destructive but behind confirmation dialog in the UI.Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/a552048be935482f9d207034f344c4e9