feat(api): add tables and files v1 REST API with OpenAPI docs#3422
feat(api): add tables and files v1 REST API with OpenAPI docs#3422waleedlatif1 merged 16 commits intofeat/mothership-copilotfrom
Conversation
PR SummaryHigh Risk Overview Updates API docs and hardens existing table routes. Extends Written by Cursor Bugbot for commit 437c332. Configure here. |
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Greptile SummaryThis PR introduces v1 REST API endpoints for tables (full CRUD, batch operations, upsert) and files (list, upload, download, delete), backed by a refactored The route-layer implementation is well-structured — JSON parse errors are guarded, empty filters are rejected via schema validation, audit events are fired, the upsert endpoint runs inside a However, the service layer has three unresolved data-integrity issues under concurrent load that affect core row-mutation operations:
These issues should be fixed before this API is used in production, especially since this is a public-facing API that modifies user data and no automated tests were added for the new endpoints. Confidence Score: 2/5
Sequence DiagramsequenceDiagram
participant ClientA as Client A (PATCH row X)
participant ClientB as Client B (PATCH row Y)
participant Service as updateRow()
participant DB as Database
ClientA->>Service: PATCH /rows/X {email: "a@b.com"}
ClientB->>Service: PATCH /rows/Y {email: "a@b.com"}
Service->>DB: checkUniqueConstraintsDb (for A) — no duplicate found ✓
Service->>DB: checkUniqueConstraintsDb (for B) — no duplicate found ✓
Note over Service,DB: No transaction — race window open
Service->>DB: UPDATE row X SET email="a@b.com"
Service->>DB: UPDATE row Y SET email="a@b.com"
Note over DB: ⚠️ Both rows now have email="a@b.com"<br/>Unique constraint violated silently
|
|
@cursor review |
|
@greptile |
|
@greptile |
|
@cursor review |
|
@greptile |
|
@cursor review |
…rors - Add 'Unique constraint violation' to upsert error classification - Wrap PUT/DELETE request.json() in try/catch to return 400 on malformed body - Apply fixes to both v1 and internal routes
|
@greptile |
- Wrap PATCH request.json() in try/catch for both v1 and internal routes - Rewrite deleteRowsByIds to use .returning() for accurate deletedCount under concurrent requests (eliminates SELECT-then-DELETE race)
|
@greptile |
|
@cursor review |
- Wrap POST handler request.json() in try/catch across all table routes - Also fix internal DELETE single-row handler - Every request.json() in table routes now returns 400 on malformed body
- Replace unsafe `as string | null` cast with typeof check - Prevents File object from bypassing workspaceId validation
|
@greptile |
|
@cursor review |
…aw() - Use instanceof File check instead of unsafe `as File | null` cast - Add regex validation on column name before sql.raw() interpolation
- Guard request.formData() with try/catch in file upload - Guard all .toISOString() calls with instanceof Date checks - Replace verifyTableWorkspace double-fetch with direct comparison - Fix relative imports to absolute (@/app/api/table/utils) - Fix internal list tables leaking fields via ...t spread - Normalize schema in internal POST create table response - Remove redundant pre-check in internal create (service handles atomically) - Make 'maximum table limit' return 403 consistently (was 400 in internal) - Add 'Row not found' → 404 classification in PATCH handlers - Add NAME_PATTERN validation before sql.raw() in validation.ts
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Summary
Type of Change
Testing
Tested manually
Checklist