Archive code-review-fix change and sync specs to main
- Synced 14 capability delta specs to main specs - Created 6 new main specs: api-authentication, error-boundary, input-validation, security-headers, shared-types - Updated 8 existing specs with security, validation, and performance requirements - Archived change to openspec/changes/archive/2026-02-20-code-review-fix/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
adb93a2d2e
commit
925e7284e3
32 changed files with 691 additions and 4 deletions
|
|
@ -0,0 +1,74 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Generic error responses
|
||||
All Next.js API routes SHALL return generic error messages to clients for 500-level errors. The response body SHALL be `{ "error": "Internal server error" }`. The full error details SHALL be logged server-side via `console.error` with request context.
|
||||
|
||||
#### Scenario: Internal error returns generic message
|
||||
- **WHEN** an API route handler throws an unexpected error
|
||||
- **THEN** the client receives HTTP 500 with `{ "error": "Internal server error" }` and the full error is logged server-side
|
||||
|
||||
#### Scenario: No stack traces in response
|
||||
- **WHEN** a database query fails in any API route
|
||||
- **THEN** the response does NOT contain table names, file paths, connection strings, or stack traces
|
||||
|
||||
### Requirement: Scoped bulk annotation delete
|
||||
The `DELETE /api/annotations` endpoint SHALL require a `chartId` query parameter when `all=true` is specified. Unscoped delete-all (without chartId) SHALL be rejected with HTTP 400.
|
||||
|
||||
#### Scenario: Scoped bulk delete
|
||||
- **WHEN** `DELETE /api/annotations?all=true&chartId=5` is called
|
||||
- **THEN** all annotations for chart 5 are deleted
|
||||
|
||||
#### Scenario: Unscoped bulk delete rejected
|
||||
- **WHEN** `DELETE /api/annotations?all=true` is called without chartId
|
||||
- **THEN** the route returns HTTP 400 with `{ "error": "chartId is required for bulk delete" }`
|
||||
|
||||
### Requirement: Transaction-wrapped chart cascade delete
|
||||
The `DELETE /api/charts/[id]` route SHALL wrap all related deletions (annotations, span annotations, candles, chart) in a single database transaction using `db.transaction()`.
|
||||
|
||||
#### Scenario: Cascade delete in transaction
|
||||
- **WHEN** `DELETE /api/charts/5` is called
|
||||
- **THEN** span annotations, annotations, candles, and the chart record for chart 5 are all deleted within a single transaction
|
||||
|
||||
#### Scenario: Partial failure rolls back
|
||||
- **WHEN** the candles deletion fails mid-transaction
|
||||
- **THEN** all deletions are rolled back and the chart remains intact
|
||||
|
||||
### Requirement: Span annotations included in chart cascade delete
|
||||
The `DELETE /api/charts/[id]` route SHALL delete span annotations for the chart in addition to annotations and candles.
|
||||
|
||||
#### Scenario: Span annotations deleted with chart
|
||||
- **WHEN** `DELETE /api/charts/5` is called
|
||||
- **THEN** all `span_annotations` rows with `chart_id=5` are deleted before the chart record
|
||||
|
||||
### Requirement: parseInt validation
|
||||
All API routes that parse integer query parameters SHALL use `parseInt(value, 10)` with radix 10 and check for `isNaN()`. Invalid integer parameters SHALL return HTTP 400.
|
||||
|
||||
#### Scenario: Valid integer parameter
|
||||
- **WHEN** `GET /api/candles?chartId=5` is called
|
||||
- **THEN** chartId is parsed as integer 5
|
||||
|
||||
#### Scenario: Invalid integer parameter
|
||||
- **WHEN** `GET /api/candles?chartId=abc` is called
|
||||
- **THEN** the route returns HTTP 400 with `{ "error": "Invalid chartId" }`
|
||||
|
||||
### Requirement: CSV injection protection on exports
|
||||
All CSV export routes SHALL prefix cell values starting with `=`, `+`, `-`, or `@` with a single quote (`'`) to prevent spreadsheet formula injection.
|
||||
|
||||
#### Scenario: Dangerous cell value escaped
|
||||
- **WHEN** an annotation note contains `=CMD("calc")`
|
||||
- **THEN** the exported CSV cell contains `'=CMD("calc")`
|
||||
|
||||
#### Scenario: Normal values unchanged
|
||||
- **WHEN** an annotation note contains `regular text`
|
||||
- **THEN** the exported CSV cell contains `regular text` (no prefix)
|
||||
|
||||
### Requirement: response.ok checks on all fetch calls
|
||||
All `fetch()` calls in frontend components (`page.tsx`, `CandleChart.tsx`) SHALL check `response.ok` before calling `response.json()`. If `!response.ok`, the code SHALL throw an error or handle the failure explicitly.
|
||||
|
||||
#### Scenario: Successful response parsed
|
||||
- **WHEN** a fetch call returns HTTP 200
|
||||
- **THEN** `response.json()` is called and the data is used normally
|
||||
|
||||
#### Scenario: Error response handled
|
||||
- **WHEN** a fetch call returns HTTP 500
|
||||
- **THEN** the code detects `!response.ok` and shows an error message instead of attempting JSON parse
|
||||
Loading…
Add table
Add a link
Reference in a new issue