candle-annotator/openspec/changes/multi-chart-management/specs/chart-management/spec.md
Marko Djordjevic 92d3339a48 feat: add charts table schema and migration with data backfill
- Add charts table with id, name (unique), created_at
- Add chart_id FK to candles table with composite unique on (chart_id, time)
- Add chart_id FK to annotations table
- Custom migration handles existing data: creates 'Imported Data' chart and backfills chart_id
- Recreates tables for NOT NULL constraint (SQLite limitation)
2026-02-13 00:12:21 +01:00

79 lines
4.3 KiB
Markdown

## ADDED Requirements
### Requirement: Charts database table
The system SHALL store chart datasets in a `charts` table with columns: `id` (integer primary key, auto-increment), `name` (text, unique), `created_at` (integer, Unix timestamp). Each chart represents a distinct uploaded CSV dataset.
#### Scenario: Schema structure
- **WHEN** the database is initialized
- **THEN** the `charts` table exists with all required columns and constraints
#### Scenario: Unique chart names
- **WHEN** a chart is created with a name that already exists
- **THEN** the system appends a numeric suffix (e.g., "btc-daily-2") to ensure uniqueness
### Requirement: Chart selector in sidebar
The system SHALL display a chart selector component in the sidebar, positioned between the app title/header section and the file upload section. The selector SHALL show the name of the currently active chart and allow the user to switch between all available charts.
#### Scenario: Chart selector renders with charts
- **WHEN** one or more charts exist in the database
- **THEN** the sidebar displays a selector showing the active chart name, with a dropdown listing all available charts sorted by creation date (newest first)
#### Scenario: Chart selector with no charts
- **WHEN** no charts exist in the database
- **THEN** the selector displays a placeholder message "No charts — upload a CSV to get started"
#### Scenario: Switch active chart
- **WHEN** user selects a different chart from the selector dropdown
- **THEN** the system updates `activeChartId` state, fetches candles and annotations for the selected chart, and re-renders the chart and sidebar label list
#### Scenario: Active chart persistence on page load
- **WHEN** the page loads and charts exist
- **THEN** the system selects the most recently created chart as the active chart
### Requirement: Delete chart
The system SHALL allow users to delete a chart and all its associated candles and annotations.
#### Scenario: Delete chart with confirmation
- **WHEN** user clicks the delete button next to a chart in the selector
- **THEN** the system displays a confirmation dialog: "Delete chart '{name}' and all its candles and annotations? This cannot be undone."
#### Scenario: Confirm chart deletion
- **WHEN** user confirms chart deletion
- **THEN** the system deletes the chart, all its candles, and all its annotations from the database, removes the chart from the selector, and switches to the next available chart (or shows empty state if none remain)
#### Scenario: Cancel chart deletion
- **WHEN** user cancels chart deletion
- **THEN** no data is deleted and the dialog closes
#### Scenario: Delete last chart
- **WHEN** user deletes the only remaining chart
- **THEN** the system shows the empty state with no chart selected and prompts the user to upload a CSV
### Requirement: List charts API
The system SHALL provide a `GET /api/charts` endpoint that returns all charts as a JSON array, ordered by `created_at` descending. Each chart object SHALL include: `id`, `name`, `created_at`.
#### Scenario: Fetch all charts
- **WHEN** GET /api/charts is called
- **THEN** endpoint returns a JSON array of chart objects ordered by created_at descending with HTTP 200
#### Scenario: No charts exist
- **WHEN** GET /api/charts is called and no charts exist
- **THEN** endpoint returns an empty JSON array `[]` with HTTP 200
### Requirement: Delete chart API
The system SHALL provide a `DELETE /api/charts/[id]` endpoint that deletes a chart and all its associated candles and annotations within a single transaction.
#### Scenario: Delete existing chart
- **WHEN** DELETE /api/charts/5 is called and chart with id 5 exists
- **THEN** endpoint deletes the chart, all candles with chart_id 5, and all annotations with chart_id 5, then returns `{ "success": true }` with HTTP 200
#### Scenario: Delete non-existent chart
- **WHEN** DELETE /api/charts/999 is called and no chart with that id exists
- **THEN** endpoint returns `{ "error": "Chart not found" }` with HTTP 404
### Requirement: Auto-select new chart after upload
The system SHALL automatically switch to the newly created chart after a successful CSV upload.
#### Scenario: Upload creates and selects chart
- **WHEN** user uploads a CSV and the upload succeeds
- **THEN** the system creates a new chart, inserts candle data for that chart, adds the chart to the selector, and sets it as the active chart