feat: add Projects management feature#470
feat: add Projects management feature#470devin-ai-integration[bot] wants to merge 1 commit intomainfrom
Conversation
- Add projects table to database schema with name, description, client_id, start_date, status fields - Add Joi validation schemas for project create/update - Add full CRUD API routes at /api/projects with client existence verification - Add 37 backend tests covering all project endpoints and error cases - Add ProjectsPage frontend component with table view and create/edit dialog - Add Project types and API client methods - Add Projects nav item to sidebar layout - Add /projects route to app router
🤖 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:
|
| }; | ||
|
|
||
| if (clientId) { | ||
| db.get('SELECT id FROM clients WHERE id = ?', [clientId], (err, row) => { |
There was a problem hiding this comment.
🔴 Missing user_email filter in client ownership check allows cross-user data access (POST)
When creating a project with a clientId, the client existence query at backend/src/routes/projects.js:113 is SELECT id FROM clients WHERE id = ?, which only checks if the client exists globally — not that it belongs to the authenticated user. Every other route in the codebase filters by user_email when checking client ownership (e.g., backend/src/routes/clients.js:118, backend/src/routes/workEntries.js:92). This allows User A to associate their project with User B's client ID, and since the GET queries use a LEFT JOIN to fetch client_name, User A would also see User B's client name — a cross-user information leakage.
| db.get('SELECT id FROM clients WHERE id = ?', [clientId], (err, row) => { | |
| db.get('SELECT id FROM clients WHERE id = ? AND user_email = ?', [clientId, req.userEmail], (err, row) => { |
Was this helpful? React with 👍 or 👎 to provide feedback.
|
|
||
| // If clientId is being updated, verify it exists | ||
| if (value.clientId) { | ||
| db.get('SELECT id FROM clients WHERE id = ?', [value.clientId], (err, clientRow) => { |
There was a problem hiding this comment.
🔴 Missing user_email filter in client ownership check allows cross-user data access (PUT)
Same issue as in the POST route: when updating a project's clientId, the client verification query at backend/src/routes/projects.js:227 is SELECT id FROM clients WHERE id = ? without filtering by the authenticated user's email. This is inconsistent with the established pattern used throughout the codebase (e.g., backend/src/routes/workEntries.js:176, backend/src/routes/clients.js:118) and allows a user to reassign their project to another user's client.
| db.get('SELECT id FROM clients WHERE id = ?', [value.clientId], (err, clientRow) => { | |
| db.get('SELECT id FROM clients WHERE id = ? AND user_email = ?', [value.clientId, req.userEmail], (err, clientRow) => { |
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Adds a new "Projects" resource to the app with full backend CRUD API, frontend UI page, and backend unit tests. Projects have a name, description, optional client assignment, optional start date, and a status (
active/completed/on-hold). Projects are scoped per-user (same pattern as work entries).Backend:
projectstable ininit.jswith foreign keys toclients(SET NULL on delete) andusers(CASCADE on delete), plus a CHECK constraint on statusprojectSchema,updateProjectSchema) inschemas.jsroutes/projects.js: list, get by id, create, update, delete one, delete all/api/projectsinserver.jsFrontend:
ProjectsPage.tsx— table view with create/edit dialog, client dropdown, status dropdown, date pickertypes/api.tsandapi/client.tsLayout.tsx) and route added toApp.tsxReview & Testing Checklist for Human
user_email—SELECT id FROM clients WHERE id = ?is used when verifying a client exists during project create/update. Since theclientstable onmainis user-scoped, this means a user could potentially assign a project to another user's client. Verify whether this is acceptable or ifAND user_email = ?should be added./projects, create a project (with and without client assignment), edit the status, delete a project, and verify the "Clear All" button works. Check that the client dropdown populates correctly.labelprop on both<Select>components produces proper notched outlines (no strikethrough).startDateround-trips correctly (frontend sendsYYYY-MM-DDstring, backend stores it, frontend displays it viatoLocaleDateString()). Timezone offsets may cause off-by-one display issues depending on locale.Notes
CreateProjectRequestandUpdateProjectRequestTypeScript interfaces are defined intypes/api.tsbut are not imported by the API client or page component (inline types are used instead). Harmless but could be cleaned up.ON DELETE SET NULLfor the client FK — if a client is deleted, the project remains butclient_idbecomes null. This is intentional.useQuery(['clients'])) to populate the client dropdown in the project form. This reuses the existing clients API.Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/21a7ea2e9e9f47f0ac809d285964aadf