## 1. Database Schema & Migrations

- [x] 1.1 Add `span_label_types` table to Drizzle schema (id, name, display_name, color, hotkey, is_active, sort_order, created_at)
- [x] 1.2 Add `span_annotations` table to Drizzle schema (id, chart_id FK, start_time, end_time, label, confidence, outcome, notes, sub_spans JSON, color, created_at)
- [x] 1.3 Run migration to create both tables
- [x] 1.4 Seed `span_label_types` with default labels: bull_flag, bear_flag, head_and_shoulders, double_bottom, wedge_up, wedge_down, custom (with distinct colors and hotkeys 1-7)

## 2. Span Label Types API

- [x] 2.1 Create `GET /api/span-label-types` endpoint — return all active label types sorted by sort_order
- [x] 2.2 Create `POST /api/span-label-types` endpoint — create a new label type
- [x] 2.3 Create `PATCH /api/span-label-types/[id]` endpoint — update label type fields
- [x] 2.4 Create `DELETE /api/span-label-types/[id]` endpoint — delete a label type

## 3. Span Annotations CRUD API

- [x] 3.1 Create `GET /api/span-annotations?chartId=X` endpoint — return all span annotations for a chart, sorted by start_time desc
- [x] 3.2 Create `POST /api/span-annotations` endpoint — create span annotation with start/end time swap validation (start <= end)
- [x] 3.3 Create `PATCH /api/span-annotations/[id]` endpoint — update label, confidence, outcome, notes, sub_spans
- [x] 3.4 Create `DELETE /api/span-annotations/[id]` endpoint — delete a span annotation

## 4. SpanRectanglePrimitive (Chart Rendering)

- [x] 4.1 Create `SpanRectanglePrimitive.ts` implementing `ISeriesPrimitive` with data-space rectangle coordinates (start_time, end_time, max_high, min_low)
- [x] 4.2 Implement `updateAllViews()` with a pane renderer that converts time/price to pixel coordinates and draws a filled semi-transparent rectangle using `useBitmapCoordinateSpace`
- [x] 4.3 Implement label tag text rendering above the rectangle (pattern name)
- [x] 4.4 Implement `hitTest()` to detect clicks within the rectangle bounds
- [x] 4.5 Add highlight state (thicker border / increased opacity) for selected spans
- [x] 4.6 Set `zOrder: 'bottom'` so rectangles render behind candlesticks

## 5. Span Tool State & Integration

- [x] 5.1 Extend `activeTool` type in `page.tsx` to include `'span'` tool mode
- [x] 5.2 Add span-related state to `page.tsx`: `spanAnnotations[]`, `selectedSpanId`, `spanLabelTypes[]`
- [x] 5.3 Add `fetchSpanAnnotations(chartId)` and `fetchSpanLabelTypes()` data fetching functions
- [x] 5.4 Load span annotations and label types when chart changes (alongside existing annotation loading)
- [x] 5.5 Add "Span" tool button to Toolbox component alongside existing tools

## 6. Two-Click Span Selection & Preview

- [x] 6.1 Create `SpanAnnotationManager.tsx` component that manages span interaction state (idle / first-click-done / popover-open)
- [x] 6.2 Implement first-click handler: snap to nearest candle, store start candle, render start marker via a preview primitive
- [x] 6.3 Implement mouse-move preview: stretch preview rectangle from start candle to cursor candle, computing price range (min low to max high) of candles in range
- [x] 6.4 Implement second-click handler: snap to nearest candle, finalize span range, swap if end < start, trigger popover
- [x] 6.5 Implement Escape key to cancel span selection and clear preview

## 7. Label Assignment Popover

- [x] 7.1 Create `SpanPopover.tsx` with shadcn Popover/Dialog: label dropdown (from span_label_types), confidence slider (1-5), outcome select (win/loss/breakeven/none), notes textarea, Save/Cancel buttons
- [x] 7.2 Position popover near the end-click position with collision avoidance
- [x] 7.3 Wire Save button: POST to API, attach SpanRectanglePrimitive to chart series, update spanAnnotations state, close popover
- [x] 7.4 Wire Cancel button / Escape: discard span, clear preview, close popover
- [x] 7.5 Disable Save when no label is selected (validation)

## 8. Span Selection, Editing & Deletion

- [x] 8.1 Implement span click-to-select using hitTest: set selectedSpanId, highlight rectangle, scroll sidebar list to selected item
- [x] 8.2 Implement click-to-deselect (click selected span again or click outside any span)
- [x] 8.3 Implement double-click / Enter to open edit popover pre-populated with current span data
- [x] 8.4 Wire edit Save: PATCH to API, update primitive color/label, update state
- [x] 8.5 Implement Delete/Backspace keyboard shortcut for selected span: DELETE API call, remove primitive, clear selection, update state
- [x] 8.6 Implement delete-tool click on span rectangle: same DELETE flow as keyboard shortcut

## 9. Span Annotation Sidebar List

- [x] 9.1 Create `SpanAnnotationList.tsx` component: scrollable list of span annotations sorted by start_time desc, showing time range, label with colored badge, delete button
- [x] 9.2 Add count summary grouped by label type (e.g., "Bull Flag: 3 | Bear Flag: 2")
- [x] 9.3 Implement click-to-select in list: set selectedSpanId, highlight chart rectangle, scroll chart to center on span's time range
- [x] 9.4 Highlight selected span entry in list (background/border)
- [x] 9.5 Wire delete button per list item: DELETE API call, remove primitive, update state
- [x] 9.6 Show empty state message when no span annotations exist
- [x] 9.7 Clear and reload span list when active chart changes

## 10. Hotkey Label Assignment

- [x] 10.1 Add keydown listener for span label hotkeys (active only when span tool is active and span range is selected)
- [x] 10.2 On hotkey press: save span with mapped label (default confidence/outcome/notes), render rectangle, update sidebar — skip popover
- [x] 10.3 Ignore hotkeys when span tool is inactive or no span range selected

## 11. Export Endpoints

- [x] 11.1 Create `GET /api/export/spans?chartId=X&format=json` — Raw Annotations JSON export with full metadata
- [x] 11.2 Create `GET /api/export/spans?chartId=X&format=windowed` — Windowed Classification CSV with flattened OHLCV columns and configurable `context_padding` (default 10)
- [x] 11.3 Create `GET /api/export/spans?chartId=X&format=bio` — BIO-tagged CSV with one row per candle, B-{label}/I-{label}/O tagging, multi-label columns for overlapping spans

## 12. Integration Testing & Polish

- [x] 12.1 Verify full create flow: activate span tool → two clicks → popover → save → rectangle renders → sidebar updates
- [x] 12.2 Verify edit flow: select span → double-click → edit popover → save → updates reflect
- [x] 12.3 Verify delete flow: select span → Delete key / trash icon → removed from chart and sidebar
- [x] 12.4 Verify chart switch: span annotations and sidebar list reload for new chart
- [x] 12.5 Verify all three export formats produce correct output
- [x] 12.6 Verify hotkey label assignment works end-to-end
