- 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>
68 lines
5.6 KiB
Markdown
68 lines
5.6 KiB
Markdown
## ADDED Requirements
|
|
|
|
### Requirement: Users table schema
|
|
The Drizzle schema SHALL define a `users` table with columns: `id` (uuid, primary key, default `gen_random_uuid()`), `name` (text, nullable), `email` (text, unique, not null), `email_verified` (timestamp, nullable), `password_hash` (text, nullable), `image` (text, nullable), `provider` (text, not null, default 'credentials'), `provider_account_id` (text, nullable), `created_at` (timestamp, not null, default now), `updated_at` (timestamp, not null, default now).
|
|
|
|
#### Scenario: Users table created
|
|
- **WHEN** the schema is loaded and migrations are applied
|
|
- **THEN** the `users` table exists with all specified columns and the `email` unique constraint
|
|
|
|
#### Scenario: UUID primary key generation
|
|
- **WHEN** a new user is inserted without specifying an ID
|
|
- **THEN** a UUID is automatically generated via `gen_random_uuid()`
|
|
|
|
## MODIFIED Requirements
|
|
|
|
### Requirement: PostgreSQL schema definitions
|
|
The Drizzle schema SHALL define all frontend tables using `pgTable` from `drizzle-orm/pg-core`. The following tables SHALL be defined: `users`, `charts`, `candles`, `annotation_types`, `annotations`, `span_label_types`, `span_annotations`. All tables except `users` and `candles` SHALL include a `user_id` column (uuid, foreign key to users.id, not null). The `candles` table inherits user scope through its `chart_id` foreign key to `charts`.
|
|
|
|
#### Scenario: Charts table schema
|
|
- **WHEN** the schema is loaded
|
|
- **THEN** the `charts` table has columns: `id` (serial, primary key), `name` (text, not null), `user_id` (uuid, foreign key to users.id, not null), `created_at` (timestamp, not null, default now), with a unique index on `(user_id, name)`
|
|
|
|
#### Scenario: Candles table schema
|
|
- **WHEN** the schema is loaded
|
|
- **THEN** the `candles` table has columns: `id` (serial, primary key), `chart_id` (integer, foreign key to charts.id, not null), `time` (timestamp, not null), `open` (double precision, not null), `high` (double precision, not null), `low` (double precision, not null), `close` (double precision, not null), with a unique index on `(chart_id, time)`
|
|
|
|
#### Scenario: Annotation types table schema
|
|
- **WHEN** the schema is loaded
|
|
- **THEN** the `annotation_types` table has columns: `id` (serial, primary key), `name` (text, not null), `display_name` (text, not null), `color` (text, not null), `category` (text, not null), `icon` (text, nullable), `is_active` (boolean, not null, default true), `user_id` (uuid, foreign key to users.id, not null), `created_at` (timestamp, not null, default now), with a unique index on `(user_id, name)`
|
|
|
|
#### Scenario: Annotations table schema
|
|
- **WHEN** the schema is loaded
|
|
- **THEN** the `annotations` table has columns: `id` (serial, primary key), `chart_id` (integer, foreign key to charts.id, not null), `timestamp` (timestamp, not null), `label_type` (text, not null), `geometry` (jsonb, nullable), `color` (text, default '#3b82f6'), `user_id` (uuid, foreign key to users.id, not null), `created_at` (timestamp, not null, default now)
|
|
|
|
#### Scenario: Span label types table schema
|
|
- **WHEN** the schema is loaded
|
|
- **THEN** the `span_label_types` table has columns: `id` (serial, primary key), `name` (text, not null), `display_name` (text, not null), `color` (text, not null), `hotkey` (text, nullable), `is_active` (boolean, not null, default true), `sort_order` (integer, not null, default 0), `user_id` (uuid, foreign key to users.id, not null), `created_at` (timestamp, not null, default now), with a unique index on `(user_id, name)`
|
|
|
|
#### Scenario: Span annotations table schema
|
|
- **WHEN** the schema is loaded
|
|
- **THEN** the `span_annotations` table has columns: `id` (serial, primary key), `chart_id` (integer, foreign key to charts.id, not null), `start_time` (timestamp, not null), `end_time` (timestamp, not null), `label` (text, not null), `confidence` (integer, nullable), `outcome` (text, nullable), `notes` (text, nullable), `sub_spans` (jsonb, nullable), `color` (text, not null, default '#2196F3'), `source` (text, not null, default 'human'), `model_prediction` (jsonb, nullable), `user_id` (uuid, foreign key to users.id, not null), `created_at` (timestamp, not null, default now)
|
|
|
|
## ADDED Requirements
|
|
|
|
### Requirement: User data migration script
|
|
The project SHALL include a migration script that adds `user_id` to existing tables, creates a default admin user, assigns all existing data to that user, and makes `user_id` NOT NULL.
|
|
|
|
#### Scenario: Migration adds user_id columns
|
|
- **WHEN** the migration runs on a database without `user_id` columns
|
|
- **THEN** `user_id` (uuid, nullable) columns are added to `charts`, `annotation_types`, `annotations`, `span_label_types`, `span_annotations`
|
|
|
|
#### Scenario: Default admin user created
|
|
- **WHEN** the migration runs and no users exist
|
|
- **THEN** a default admin user is created with email from `DEFAULT_ADMIN_EMAIL` env var (default: `admin@candleannotator.local`) and password from `DEFAULT_ADMIN_PASSWORD` env var (default: `changeme123`)
|
|
|
|
#### Scenario: Existing data assigned to admin
|
|
- **WHEN** the migration runs and existing rows have NULL `user_id`
|
|
- **THEN** all rows are updated to set `user_id` to the admin user's ID
|
|
|
|
#### Scenario: Columns made NOT NULL
|
|
- **WHEN** all existing rows have been assigned a `user_id`
|
|
- **THEN** the `user_id` columns are altered to NOT NULL with foreign key constraints
|
|
|
|
#### Scenario: Unique constraints updated
|
|
- **WHEN** the migration completes
|
|
- **THEN** the unique constraint on `charts.name` is replaced with `(user_id, name)`
|
|
- **AND** the unique constraint on `annotation_types.name` is replaced with `(user_id, name)`
|
|
- **AND** the unique constraint on `span_label_types.name` is replaced with `(user_id, name)`
|