Implement task 6.1: Create PUT /api/auth/profile endpoint for updating user display name
- Create src/app/api/auth/profile/route.ts with PUT handler - Validates user is authenticated (returns 401 if not) - Validates request body has a non-empty name field - Updates user's name in the database - Returns 200 with updated user data Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d4e92cf88f
commit
c36ab7c146
27 changed files with 2699 additions and 2 deletions
113
openspec/changes/user-accounts/specs/backend-api/spec.md
Normal file
113
openspec/changes/user-accounts/specs/backend-api/spec.md
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
## MODIFIED 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 require authentication via `getAuthUser()`. The route SHALL forward the request body (pair, timeframe, candles array) and include the `X-User-ID` header with the authenticated user's UUID. If the inference service is unreachable, the route SHALL return HTTP 503 with `{ "error": "Inference service unavailable" }`.
|
||||
|
||||
#### Scenario: Successful prediction proxy
|
||||
- **WHEN** an authenticated user calls POST /api/predict with valid candle data and the Python service is running
|
||||
- **THEN** the route forwards the request with `X-User-ID` header and returns the prediction response with HTTP 200
|
||||
|
||||
#### Scenario: Unauthenticated prediction request
|
||||
- **WHEN** POST /api/predict is called without authentication
|
||||
- **THEN** the route returns HTTP 401 with `{ "error": "Unauthorized" }`
|
||||
|
||||
#### 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 require authentication and include the `X-User-ID` header.
|
||||
|
||||
#### Scenario: Successful batch prediction
|
||||
- **WHEN** an authenticated user calls POST /api/predict/batch with valid parameters
|
||||
- **THEN** the route forwards to the inference service with `X-User-ID` header and returns the 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: 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`. All training proxy routes SHALL require authentication and include the `X-User-ID` header.
|
||||
|
||||
#### Scenario: Proxy training start
|
||||
- **WHEN** an authenticated user calls POST /api/training/start
|
||||
- **THEN** the route forwards to the FastAPI service with `X-User-ID` header
|
||||
|
||||
#### Scenario: Proxy training runs
|
||||
- **WHEN** an authenticated user calls GET /api/training/runs
|
||||
- **THEN** the route forwards to the FastAPI service with `X-User-ID` header 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. The route SHALL require authentication and include the `X-User-ID` header.
|
||||
|
||||
#### Scenario: Proxy model load
|
||||
- **WHEN** an authenticated user calls POST /api/model/load with a run_id
|
||||
- **THEN** the route forwards to the FastAPI service with `X-User-ID` header
|
||||
|
||||
### 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`. The route SHALL require authentication and include the `X-User-ID` header.
|
||||
|
||||
#### Scenario: Successful model info
|
||||
- **WHEN** an authenticated user calls GET /api/model/info
|
||||
- **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" }`
|
||||
|
||||
### Requirement: Pattern detection proxy
|
||||
The Next.js API SHALL provide a `POST /api/patterns/detect` route that proxies to the FastAPI `/patterns/detect` endpoint. The route SHALL require authentication and include the `X-User-ID` header.
|
||||
|
||||
#### Scenario: Proxy pattern detection
|
||||
- **WHEN** an authenticated user calls POST /api/patterns/detect
|
||||
- **THEN** the route forwards the request with `X-User-ID` header 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. The route SHALL require authentication.
|
||||
|
||||
#### Scenario: Proxy available patterns
|
||||
- **WHEN** an authenticated user calls GET /api/patterns/available
|
||||
- **THEN** the route forwards to the FastAPI service and returns the pattern list
|
||||
|
||||
### Requirement: Bulk delete by source
|
||||
The Next.js API `DELETE /api/span-annotations` endpoint SHALL require authentication and scope deletion by the authenticated user. When `source` is provided, all span annotations matching that source (and optionally `label` filter) for the current chart belonging to the authenticated user SHALL be deleted.
|
||||
|
||||
#### Scenario: Bulk delete TA-Lib annotations
|
||||
- **WHEN** an authenticated user calls `DELETE /api/span-annotations?chartId=1&source=talib`
|
||||
- **THEN** all span annotations with `source: "talib"` for chart 1 belonging to that user are deleted
|
||||
|
||||
#### Scenario: Bulk delete by source and label
|
||||
- **WHEN** an authenticated user calls `DELETE /api/span-annotations?chartId=1&source=talib&label=Engulfing`
|
||||
- **THEN** only TA-Lib annotations containing "Engulfing" for chart 1 belonging to that user are deleted
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Auth guard on all data API routes
|
||||
All existing data API routes (`/api/upload`, `/api/candles`, `/api/annotations`, `/api/annotation-types`, `/api/charts`, `/api/span-annotations`, `/api/span-label-types`, `/api/export`) SHALL call `getAuthUser()` at the top. If the user is not authenticated, the route SHALL return HTTP 401.
|
||||
|
||||
#### Scenario: Unauthenticated data API access
|
||||
- **WHEN** any data API route is called without authentication
|
||||
- **THEN** the route returns HTTP 401 with `{ "error": "Unauthorized" }`
|
||||
|
||||
#### Scenario: Authenticated data API access
|
||||
- **WHEN** any data API route is called with valid authentication
|
||||
- **THEN** the route proceeds with queries scoped to the authenticated user's ID
|
||||
|
||||
### Requirement: User-scoped queries in all data routes
|
||||
All Drizzle queries in data API routes SHALL include a `user_id` filter matching the authenticated user. INSERT operations SHALL set `user_id` to the authenticated user's UUID.
|
||||
|
||||
#### Scenario: GET queries filtered by user
|
||||
- **WHEN** an authenticated user requests data (charts, annotations, annotation types, etc.)
|
||||
- **THEN** the query includes `.where(eq(table.user_id, user.id))` or equivalent join condition
|
||||
|
||||
#### Scenario: INSERT operations set user_id
|
||||
- **WHEN** an authenticated user creates new data (upload, create annotation, etc.)
|
||||
- **THEN** the inserted row has `user_id` set to the authenticated user's UUID
|
||||
|
||||
#### Scenario: Cross-user data isolation
|
||||
- **WHEN** user A requests data
|
||||
- **THEN** no data belonging to user B is returned
|
||||
Loading…
Add table
Add a link
Reference in a new issue