candle-annotator/openspec/specs/backend-api/spec.md
2026-02-18 10:21:05 +01:00

9.1 KiB

ADDED Requirements

Requirement: Predict proxy endpoint

The system SHALL provide a POST /api/predict Next.js API route that proxies requests to the Python inference service at ${INFERENCE_API_URL}/predict. The route SHALL forward the request body (pair, timeframe, candles array) and return the Python service's response. If the inference service is unreachable, the route SHALL return HTTP 503 with { "error": "Inference service unavailable" }.

Scenario: Successful prediction proxy

  • WHEN POST /api/predict is called with valid candle data and the Python service is running
  • THEN the route forwards the request to the inference service and returns the prediction response with HTTP 200

Scenario: Inference service down

  • WHEN POST /api/predict is called but the Python inference service is unreachable
  • THEN the route returns HTTP 503 with { "error": "Inference service unavailable" }

Scenario: Inference service error

  • WHEN the Python inference service returns an error status (4xx or 5xx)
  • THEN the route forwards the error status and message to the client

Requirement: Batch predict proxy endpoint

The system SHALL provide a POST /api/predict/batch Next.js API route that proxies batch prediction requests to ${INFERENCE_API_URL}/predict/batch. The route SHALL forward pair, timeframe, start_date, and end_date.

Scenario: Successful batch prediction

  • WHEN POST /api/predict/batch is called with valid parameters
  • THEN the route forwards to the inference service and returns the batch prediction response

Scenario: Timeout on large batch

  • WHEN the batch prediction takes longer than INFERENCE_BATCH_TIMEOUT
  • THEN the route returns HTTP 504 with { "error": "Batch prediction timed out" }

Requirement: Pattern detection endpoint

The FastAPI service SHALL provide a POST /patterns/detect endpoint that accepts candle data and a list of CDL pattern names. The endpoint SHALL run the specified TA-Lib CDL functions on the candle data and return detected patterns as span annotation objects. Each returned annotation SHALL include start_time, end_time, label, confidence, and source ("talib").

Scenario: Detect specific patterns

  • WHEN POST /patterns/detect is called with {candles: [...], patterns: ["CDLENGULFING", "CDLHAMMER"]}
  • THEN the endpoint runs only Engulfing and Hammer detection and returns matching span annotations

Scenario: Detect all patterns

  • WHEN POST /patterns/detect is called with {candles: [...], patterns: []} (empty list)
  • THEN the endpoint runs all available CDL pattern functions

Scenario: No patterns found

  • WHEN detection runs but no patterns match
  • THEN the endpoint returns {annotations: [], metadata: {count: 0}}

Scenario: Invalid pattern name

  • WHEN a pattern name is not a valid TA-Lib CDL function
  • THEN the endpoint returns HTTP 400 with the invalid pattern name in the error message

Requirement: Available patterns endpoint

The FastAPI service SHALL provide a GET /patterns/available endpoint that returns the list of all supported CDL pattern names with their friendly display names.

Scenario: List available patterns

  • WHEN GET /patterns/available is called
  • THEN the endpoint returns a list of {function_name, display_name} for all supported CDL patterns

Requirement: Training start endpoint

The FastAPI service SHALL provide a POST /training/start endpoint that triggers a training run in a background thread. The endpoint SHALL accept {model_type} and return immediately with a run_id and status "running". Only one training run SHALL be allowed at a time.

Scenario: Start training

  • WHEN POST /training/start is called with {model_type: "random_forest"}
  • THEN the endpoint returns {run_id, status: "running"} and training begins in the background

Scenario: Training already in progress

  • WHEN POST /training/start is called while a training run is active
  • THEN the endpoint returns HTTP 409 with {error: "Training already in progress", run_id: "<active_run_id>"}

Scenario: Invalid model type

  • WHEN POST /training/start is called with an unsupported model type
  • THEN the endpoint returns HTTP 400 with {error: "Unsupported model type. Available: random_forest, xgboost"}

Requirement: Training runs endpoint

The FastAPI service SHALL provide a GET /training/runs endpoint that returns training run history from the database. Each entry SHALL include run_id, model_type, status, created_at, completed_at, and metrics_summary. Results SHALL be sorted by created_at descending.

Scenario: List training runs

  • WHEN GET /training/runs is called
  • THEN the endpoint returns training run records sorted by date descending

Scenario: No training runs

  • WHEN no training runs exist in the database
  • THEN the endpoint returns {runs: []}

Requirement: Model load endpoint

The FastAPI service SHALL provide a POST /model/load endpoint that loads a model by run_id. The endpoint SHALL look up the training run, find the model artifact (MLflow or local), and replace the currently loaded model. The endpoint SHALL return the new model's info.

Scenario: Load model by run_id

  • WHEN POST /model/load is called with {run_id: "abc123"}
  • THEN the endpoint loads the model associated with that run, updates the active model, and returns model info

Scenario: Run not found

  • WHEN POST /model/load is called with a non-existent run_id
  • THEN the endpoint returns HTTP 404 with {error: "Training run not found"}

Scenario: Model artifact missing

  • WHEN the training run exists but the model file is missing
  • THEN the endpoint returns HTTP 500 with {error: "Model artifact not found for run"}

Requirement: Dataset info endpoint

The FastAPI service SHALL provide a GET /training/dataset-info endpoint that returns information about the training dataset: file path, existence status, file size, and last modified date.

Scenario: Dataset exists

  • WHEN GET /training/dataset-info is called and the labeled dataset file exists
  • THEN the endpoint returns {path, exists: true, size_bytes, last_modified, row_count}

Scenario: Dataset missing

  • WHEN GET /training/dataset-info is called and the labeled dataset file does not exist
  • THEN the endpoint returns {path, exists: false}

Requirement: Pattern detection proxy

The Next.js API SHALL provide a POST /api/patterns/detect route that proxies to the FastAPI /patterns/detect endpoint.

Scenario: Proxy pattern detection

  • WHEN POST /api/patterns/detect is called
  • THEN the route forwards the request to the FastAPI service and returns the response

Requirement: Available patterns proxy

The Next.js API SHALL provide a GET /api/patterns/available route that proxies to the FastAPI /patterns/available endpoint.

Scenario: Proxy available patterns

  • WHEN GET /api/patterns/available is called
  • THEN the route forwards to the FastAPI service and returns the pattern list

Requirement: Training proxy endpoints

The Next.js API SHALL provide proxy routes for training operations: POST /api/training/start, GET /api/training/runs, and GET /api/training/dataset-info.

Scenario: Proxy training start

  • WHEN POST /api/training/start is called
  • THEN the route forwards to the FastAPI service and returns the response

Scenario: Proxy training runs

  • WHEN GET /api/training/runs is called
  • THEN the route forwards to the FastAPI service and returns the run list

Requirement: Model load proxy

The Next.js API SHALL provide a POST /api/model/load route that proxies to the FastAPI /model/load endpoint.

Scenario: Proxy model load

  • WHEN POST /api/model/load is called with a run_id
  • THEN the route forwards to the FastAPI service and returns the response

Requirement: Bulk delete by source

The Next.js API DELETE /api/span-annotations endpoint SHALL support a source query parameter for bulk deletion. When source is provided, all span annotations matching that source (and optionally label filter) for the current chart SHALL be deleted.

Scenario: Bulk delete TA-Lib annotations

  • WHEN DELETE /api/span-annotations?chartId=1&source=talib is called
  • THEN all span annotations with source: "talib" for chart 1 are deleted

Scenario: Bulk delete by source and label

  • WHEN DELETE /api/span-annotations?chartId=1&source=talib&label=Engulfing is called
  • THEN only TA-Lib annotations containing "Engulfing" in the label for chart 1 are deleted

Requirement: Model info proxy endpoint

The system SHALL provide a GET /api/model/info Next.js API route that proxies to ${INFERENCE_API_URL}/model/info. This endpoint returns model metadata and per-class metrics.

Scenario: Successful model info

  • WHEN GET /api/model/info is called and the inference service is running
  • THEN the route returns the model metadata JSON

Scenario: No model available

  • WHEN GET /api/model/info is called and the inference service returns 503
  • THEN the route returns HTTP 503 with { "error": "No model available" }