Added HTTP error checks before calling .json() in the three fetch
functions (fetchCandles, fetchAnnotations, fetchAnnotationTypes)
to prevent silent failures on non-2xx responses.
Marks task 4.12 as complete in tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Guard all four fetch() calls in src/app/page.tsx against non-2xx HTTP
responses by throwing before attempting to parse the body as JSON.
Affected functions: fetchCharts, fetchAnnotations, fetchSpanAnnotations,
fetchSpanLabelTypes.
Marks task 4.11 as completed in code-review-fix/tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add sanitizeCsvCell() helper to both export routes that prefixes cell
values starting with =, +, @, or - with a single quote to prevent CSV
formula injection attacks.
Applied to:
- src/app/api/export/route.ts: timestamp and label_type columns
- src/app/api/span-annotations/export/route.ts: start_time, end_time,
label, and outcome columns
Closes task 4.10.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Import spanAnnotations from schema
- Wrap all delete operations in db.transaction() for atomicity
- Delete spanAnnotations first to satisfy FK constraints, then annotations, candles, chart
- Mark task 4.8 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reject DELETE ?all=true without chartId with HTTP 400 to prevent
accidental deletion of annotations across all charts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Import z from zod
- Add CandleSchema validating time, open, high, low, close (number), volume (optional number)
- Add PatternDetectRequestSchema validating candles array and patterns array of non-empty strings
- Use safeParse() and return HTTP 400 with error details on validation failure
- Forward only validated data to the inference service
- Mark task 4.5 as completed in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Validates model_type as a non-empty string using .safeParse(); returns
HTTP 400 with error details on invalid input. Marks task 4.4 as done.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Validate run_id in POST /api/model/load using Zod:
- run_id must be a non-empty string matching /^[a-zA-Z0-9_-]+$/
- Returns HTTP 400 with error details if validation fails
- Validated data is forwarded to the inference service
Marks task 4.3 as complete in tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add BatchPredictRequestSchema with Zod to validate pair, timeframe,
start_date, and end_date fields. Returns HTTP 400 with flattened error
details on invalid input. Forward only validated data to the inference
service.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add CandleSchema validating time, open, high, low, close (number) and optional volume
- Add PredictRequestSchema validating pair (non-empty string), timeframe (non-empty string), candles array
- Use safeParse() and return HTTP 400 with error details on invalid input
- Forward only validated data to the inference service
- Mark task 4.1 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All 12 Next.js API routes that proxy requests to the ML service
(INFERENCE_API_URL / localhost:8001) now include the X-API-Key header
read from process.env.API_KEY. Affected routes:
- /api/predict
- /api/predict/batch
- /api/model/info
- /api/model/load
- /api/training/start
- /api/training/runs
- /api/training/runs/[run_id] (DELETE)
- /api/training/dataset-info
- /api/training/active
- /api/training/build-dataset
- /api/patterns/available
- /api/patterns/detect
Marks task 3.3 as complete in openspec/changes/code-review-fix/tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create src/middleware.ts with Next.js middleware
- Reads API_KEY env var and checks X-API-Key header on all /api/* routes
- Skips auth for /api/health endpoint
- Fails open (with warning) when API_KEY is not configured
- Returns 401 Unauthorized when key is missing or mismatched
- Mark task 3.1 as complete in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Validate filename ends with .csv (case-insensitive)
- Validate MIME type is text/* or application/csv or text/csv
- Return HTTP 400 with error message if validation fails
- Mark task 2.4 as complete
- Reject uploads larger than 10MB before reading file content
- Reject CSVs with more than 500,000 data rows after parsing
- Checks placed as early as possible in the handler flow
- Mark task 2.3 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Validate that run_id matches /^[a-zA-Z0-9_-]+$ regex before interpolating into the API URL.
Returns HTTP 400 with 'Invalid run_id format' error if validation fails.
This prevents potential URL injection attacks and invalid identifier usage.
- Add build_dataset_from_db() that exports candles from DB, runs feature
engineering, and ingests span annotations into labeled CSV
- Call it automatically in _run_training_background before training starts
- Add POST /training/build-dataset endpoint for standalone use
- Add Next.js proxy route /api/training/build-dataset
- Update TrainingPanel: remove dataset-missing block on Start Training,
show informational message that dataset builds automatically
- Rewrite scripts/run-migrations.js for PostgreSQL (was better-sqlite3)
- Rewrite scripts/load-initial-data.js for PostgreSQL (was better-sqlite3)
- Make db connection lazy in src/lib/db/index.ts to avoid build-time errors
when DATABASE_URL is not available in Docker build stage
- Fix SpanAnnotationManager price range calculation: use direct candle
filtering by time range instead of dummy Candle objects that fell back
to 0/0 high/low, causing invisible rectangles
- Add handleDeleteAllAnnotations in page.tsx (deletes all span annotations
and regular annotations for current chart)
- Add 'Delete All Annotations' button in sidebar below TA-Lib panel
- TalibPatternPanel: pattern checkboxes, detect button, results summary, clear-all and per-pattern delete
- TrainingPanel: model type selector, dataset info, start training, polling, run history
- ModelSelector: dropdown of completed runs, wired into PredictionPanel for model switching
- page.tsx: integrate all three panels into sidebar, wire callbacks (model load, annotations refresh)
- tasks.md: mark all 39 tasks complete
- Created scripts/migrate-sqlite-to-postgres.py as alternative to TypeScript version
- Handles all type conversions: timestamps, booleans, and JSONB fields
- Successfully migrated all 2,836 rows from SQLite to PostgreSQL
- Verified data integrity: all 6 tables migrated correctly
- Charts: 1, Candles: 2,592, Annotations: 4, Span annotations: 223
- Replace green hacker theme with professional blue-toned design
- Light theme default, manual toggle only (no system detection)
- Compact w-60 sidebar with collapsible sections
- New CSS tokens: sidebar, chart, candle, annotation colors
- Tools displayed as compact grid buttons
- Color swatches as inline bar
- Chart top bar with keyboard shortcut hints
- Inter + JetBrains Mono font pairing
- All components updated for compact styling
- Tailwind config extended with sidebar/chart tokens
- Add scripts/run-migrations.js to run migrations before data loading
- Fix startup.sh ordering: migrations -> data load -> app start
- Fix migration 0005 missing statement-breakpoint between ALTER TABLE statements
- Add migration 0005 to drizzle journal (was missing)
- Fix load-initial-data.js to check table existence before querying
- Fix load-initial-data.js to create chart record before inserting candles (chart_id NOT NULL constraint)
- Simplify db/index.ts migration error handling (remove overly broad 'already exists' catch)
- Add pre-migration check for inconsistent DB state (tables without migration tracking)