feat: initialize Next.js project with database schema
- Set up Next.js with App Router, TypeScript, Tailwind CSS - Configure shadcn/ui with dark theme - Install dependencies: lightweight-charts, papaparse, lucide-react - Set up Drizzle ORM with better-sqlite3 - Create database schema for candles and annotations tables - Generate migration SQL
This commit is contained in:
parent
7d2fc42b73
commit
d04b673cfa
25 changed files with 903 additions and 0 deletions
|
|
@ -0,0 +1,75 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Upload endpoint
|
||||
The system SHALL provide a `POST /api/upload` endpoint that accepts a CSV file via multipart form data. The endpoint SHALL parse the CSV using papaparse, validate the format, and insert all candle records into the `candles` table within a single database transaction. On success, the endpoint SHALL return a JSON response with the count of inserted records. On failure, it SHALL return an appropriate error status and message.
|
||||
|
||||
#### Scenario: Successful upload
|
||||
- **WHEN** a valid CSV file is sent to POST /api/upload
|
||||
- **THEN** endpoint returns `{ "success": true, "count": <number> }` with HTTP 200
|
||||
|
||||
#### Scenario: Invalid CSV upload
|
||||
- **WHEN** a CSV with missing or invalid headers is sent to POST /api/upload
|
||||
- **THEN** endpoint returns `{ "error": "<description>" }` with HTTP 400
|
||||
|
||||
#### Scenario: No file provided
|
||||
- **WHEN** POST /api/upload is called without a file
|
||||
- **THEN** endpoint returns `{ "error": "No file provided" }` with HTTP 400
|
||||
|
||||
### Requirement: Get annotations endpoint
|
||||
The system SHALL provide a `GET /api/annotations` endpoint that returns all annotations from the database as a JSON array. Each annotation object SHALL include: `id`, `timestamp`, `label_type`, `geometry` (parsed from JSON string or null), and `created_at`.
|
||||
|
||||
#### Scenario: Fetch all annotations
|
||||
- **WHEN** GET /api/annotations is called
|
||||
- **THEN** endpoint returns a JSON array of all annotation objects with HTTP 200
|
||||
|
||||
#### Scenario: No annotations exist
|
||||
- **WHEN** GET /api/annotations is called and no annotations are in the database
|
||||
- **THEN** endpoint returns an empty JSON array `[]` with HTTP 200
|
||||
|
||||
### Requirement: Create annotation endpoint
|
||||
The system SHALL provide a `POST /api/annotations` endpoint that accepts a JSON body with fields: `timestamp` (required, integer), `label_type` (required, string), and `geometry` (optional, object). The endpoint SHALL validate the input, serialize geometry to JSON string if present, and insert the record into the `annotations` table. On success, it SHALL return the created annotation object with its assigned `id`.
|
||||
|
||||
#### Scenario: Create a marker annotation
|
||||
- **WHEN** POST /api/annotations is called with `{ "timestamp": 1700000000, "label_type": "break_up" }`
|
||||
- **THEN** endpoint saves the annotation and returns the created object with `id` and HTTP 201
|
||||
|
||||
#### Scenario: Create a line annotation
|
||||
- **WHEN** POST /api/annotations is called with `{ "timestamp": 1700000000, "label_type": "line", "geometry": { "startTime": 1700000000, "startPrice": 1.05, "endTime": 1700100000, "endPrice": 1.06 } }`
|
||||
- **THEN** endpoint saves the annotation with serialized geometry JSON and returns the created object with HTTP 201
|
||||
|
||||
#### Scenario: Invalid annotation data
|
||||
- **WHEN** POST /api/annotations is called with missing required fields
|
||||
- **THEN** endpoint returns `{ "error": "<description>" }` with HTTP 400
|
||||
|
||||
### Requirement: Delete annotation endpoint
|
||||
The system SHALL provide a `DELETE /api/annotations/[id]` endpoint that removes an annotation by its ID. On success, it SHALL return HTTP 200. If the annotation does not exist, it SHALL return HTTP 404.
|
||||
|
||||
#### Scenario: Delete existing annotation
|
||||
- **WHEN** DELETE /api/annotations/5 is called and annotation with id 5 exists
|
||||
- **THEN** endpoint removes the annotation and returns HTTP 200
|
||||
|
||||
#### Scenario: Delete non-existent annotation
|
||||
- **WHEN** DELETE /api/annotations/999 is called and no annotation with that id exists
|
||||
- **THEN** endpoint returns HTTP 404
|
||||
|
||||
### Requirement: Export annotations endpoint
|
||||
The system SHALL provide a `GET /api/export` endpoint that returns all annotations as a downloadable CSV file. The CSV SHALL have columns: `timestamp`, `label_type`, `price` (extracted from geometry for lines, or the candle's close price for markers). The response SHALL set `Content-Type: text/csv` and `Content-Disposition: attachment; filename="annotations.csv"` headers.
|
||||
|
||||
#### Scenario: Export as CSV
|
||||
- **WHEN** GET /api/export is called and annotations exist
|
||||
- **THEN** endpoint returns a CSV file download with all annotations
|
||||
|
||||
#### Scenario: Export with no data
|
||||
- **WHEN** GET /api/export is called and no annotations exist
|
||||
- **THEN** endpoint returns a CSV file with only the header row
|
||||
|
||||
### Requirement: Get candles endpoint
|
||||
The system SHALL provide a `GET /api/candles` endpoint that returns all candle records from the database as a JSON array, ordered by time ascending. Each object SHALL include: `time`, `open`, `high`, `low`, `close`.
|
||||
|
||||
#### Scenario: Fetch all candles
|
||||
- **WHEN** GET /api/candles is called
|
||||
- **THEN** endpoint returns a JSON array of candle objects ordered by time ascending with HTTP 200
|
||||
|
||||
#### Scenario: No candles exist
|
||||
- **WHEN** GET /api/candles is called and no candle data is in the database
|
||||
- **THEN** endpoint returns an empty JSON array `[]` with HTTP 200
|
||||
Loading…
Add table
Add a link
Reference in a new issue