From 103bfa89cb3e3bbef1ab04bec40688e858992fff Mon Sep 17 00:00:00 2001 From: Marko Djordjevic Date: Wed, 18 Feb 2026 11:16:37 +0100 Subject: [PATCH] fix: require chartId for bulk delete in annotations route (task 4.7) Reject DELETE ?all=true without chartId with HTTP 400 to prevent accidental deletion of annotations across all charts. Co-Authored-By: Claude Sonnet 4.6 --- openspec/changes/code-review-fix/tasks.md | 2 +- src/app/api/annotations/route.ts | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openspec/changes/code-review-fix/tasks.md b/openspec/changes/code-review-fix/tasks.md index 4c395c1..47a35ca 100644 --- a/openspec/changes/code-review-fix/tasks.md +++ b/openspec/changes/code-review-fix/tasks.md @@ -32,7 +32,7 @@ - [x] 4.4 `[sonnet]` Add Zod schema validation to `src/app/api/training/start/route.ts` (validate model_type) - [x] 4.5 `[sonnet]` Add Zod schema validation to `src/app/api/patterns/detect/route.ts` (validate candles, patterns array) - [x] 4.6 `[sonnet]` Replace `error.message` with generic `"Internal server error"` in all catch blocks across 7+ route files: `health/route.ts`, `candles/route.ts`, `annotations/route.ts`, `annotations/[id]/route.ts`, `upload/route.ts`, `export/route.ts`, `span-annotations/export/route.ts` -- [ ] 4.7 `[sonnet]` Require `chartId` for bulk delete in `src/app/api/annotations/route.ts` — reject `?all=true` without chartId with HTTP 400 +- [x] 4.7 `[sonnet]` Require `chartId` for bulk delete in `src/app/api/annotations/route.ts` — reject `?all=true` without chartId with HTTP 400 - [ ] 4.8 `[sonnet]` Wrap chart cascade delete in `db.transaction()` and add `spanAnnotations` deletion in `src/app/api/charts/[id]/route.ts` - [ ] 4.9 `[haiku]` Add `parseInt(value, 10)` with `isNaN()` guard to all routes parsing integer query params - [ ] 4.10 `[sonnet]` Add CSV injection protection (prefix `=+@-` cells with `'`) to all export routes diff --git a/src/app/api/annotations/route.ts b/src/app/api/annotations/route.ts index e2a64fa..3d87f50 100644 --- a/src/app/api/annotations/route.ts +++ b/src/app/api/annotations/route.ts @@ -102,11 +102,13 @@ export async function DELETE(request: NextRequest) { let result; if (all === 'true') { - if (chartId) { - result = await db.delete(annotations).where(eq(annotations.chart_id, parseInt(chartId, 10))).returning(); - } else { - result = await db.delete(annotations).returning(); + if (!chartId) { + return NextResponse.json( + { error: 'chartId is required for bulk delete' }, + { status: 400 } + ); } + result = await db.delete(annotations).where(eq(annotations.chart_id, parseInt(chartId, 10))).returning(); } else if (type) { const types = type.split(',').map((t) => t.trim()); if (chartId) {