candle-annotator/openspec/changes/candle-annotator-app/specs/backend-api/spec.md
Marko Djordjevic d04b673cfa 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
2026-02-12 10:23:02 +01:00

4.7 KiB

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